fix:所有采购合同号改为采购单号。销售合同号改为销售单号。
| | |
| | | // 采购-来票登记接口 |
| | | import request from "@/utils/request"; |
| | | |
| | | // 查询采购合同号 |
| | | // 查询采购单号 |
| | | export function getProduct(query) { |
| | | return request({ |
| | | url: "/purchase/ledger/getProduct", |
| | |
| | | }); |
| | | } |
| | | |
| | | // 查询id采购合同号 |
| | | // 查询id采购单号 |
| | | export function getPurchaseNoById(query) { |
| | | return request({ |
| | | url: "/purchase/ledger/getPurchaseNoById", |
| | |
| | | params: query, |
| | | }); |
| | | } |
| | | // 根据采购合同号查询详细信息 |
| | | // 根据采购单号查询详细信息 |
| | | export function getInfo(query) { |
| | | return request({ |
| | | url: "/purchase/ledger/getInfo", |
| | |
| | | method: "get", |
| | | }); |
| | | } |
| | | // 根据采购合同号查询详情 |
| | | // 根据采购单号查询详情 |
| | | export function byPurchaseId(query) { |
| | | return request({ |
| | | url: "/purchase/paymentRegistration/byPurchaseId/" + query, |
| | | method: "get", |
| | | }); |
| | | } |
| | | // 查询采购合同号 |
| | | // 查询采购单号 |
| | | export function getPurchaseNo() { |
| | | return request({ |
| | | url: "/purchase/ledger/getPurchaseNo", |
| | |
| | | }); |
| | | } |
| | | |
| | | // 根据销售合同号查产品信息 |
| | | // 根据销售单号查产品信息 |
| | | export function getProductInfoByContractNo(query) { |
| | | return request({ |
| | | url: "/purchase/ledger/getProductBySalesNo", |
| | |
| | | method: "get", |
| | | params: query, |
| | | }); |
| | | } |
| | | } |
| | |
| | | </el-row> |
| | | <el-row v-if="!isQuotationApproval && !isPurchaseApproval"> |
| | | <el-col :span="24"> |
| | | <el-form-item :label="props.approveType == 5 ? '采购合同号:' : '审批事由:'" prop="approveReason"> |
| | | <el-form-item :label="props.approveType == 5 ? '采购单号:' : '审批事由:'" prop="approveReason"> |
| | | <el-input v-model="form.approveReason" placeholder="请输入" clearable type="textarea" disabled/> |
| | | </el-form-item> |
| | | </el-col> |
| | |
| | | <el-empty v-if="!currentPurchase || !currentPurchase.purchaseContractNumber" description="未查询到对应采购详情" /> |
| | | <template v-else> |
| | | <el-descriptions :column="2" border> |
| | | <el-descriptions-item label="采购合同号">{{ currentPurchase.purchaseContractNumber }}</el-descriptions-item> |
| | | <el-descriptions-item label="采购单号">{{ currentPurchase.purchaseContractNumber }}</el-descriptions-item> |
| | | <el-descriptions-item label="供应商名称">{{ currentPurchase.supplierName }}</el-descriptions-item> |
| | | <el-descriptions-item label="项目名称">{{ currentPurchase.projectName }}</el-descriptions-item> |
| | | <el-descriptions-item label="销售合同号">{{ currentPurchase.salesContractNo }}</el-descriptions-item> |
| | | <el-descriptions-item label="销售单号">{{ currentPurchase.salesContractNo }}</el-descriptions-item> |
| | | <el-descriptions-item label="签订日期">{{ currentPurchase.executionDate }}</el-descriptions-item> |
| | | <el-descriptions-item label="录入日期">{{ currentPurchase.entryDate }}</el-descriptions-item> |
| | | <el-descriptions-item label="付款方式">{{ currentPurchase.paymentMethod }}</el-descriptions-item> |
| | |
| | | getProductOptions().then(() => { |
| | | // 确保值类型匹配(如果选项已加载) |
| | | if (productOptions.value.length > 0 && form.value.approveDeptId) { |
| | | const matchedOption = productOptions.value.find(opt => |
| | | opt.deptId == form.value.approveDeptId || |
| | | const matchedOption = productOptions.value.find(opt => |
| | | opt.deptId == form.value.approveDeptId || |
| | | String(opt.deptId) === String(form.value.approveDeptId) |
| | | ); |
| | | if (matchedOption) { |
| | |
| | | } |
| | | } |
| | | |
| | | // 采购审批:用审批事由字段承载的"采购合同号"去查采购详情 |
| | | // 采购审批:用审批事由字段承载的"采购单号"去查采购详情 |
| | | if (isPurchaseApproval.value) { |
| | | const purchaseContractNumber = row?.approveReason; |
| | | if (purchaseContractNumber) { |
| | |
| | | width: 200px; |
| | | height: 60px; |
| | | } |
| | | </style> |
| | | </style> |
| | |
| | | </el-row> |
| | | <el-row> |
| | | <el-col :span="24"> |
| | | <el-form-item :label="props.approveType == 5 ? '采购合同号:' : '审批事由:'" prop="approveReason"> |
| | | <el-form-item :label="props.approveType == 5 ? '采购单号:' : '审批事由:'" prop="approveReason"> |
| | | <el-input v-model="form.approveReason" placeholder="请输入" clearable type="textarea" /> |
| | | </el-form-item> |
| | | </el-col> |
| | |
| | | ] |
| | | form.value.approveUser = userStore.id; |
| | | form.value.approveTime = getCurrentDate(); |
| | | |
| | | |
| | | // 获取当前用户信息并设置部门ID |
| | | form.value.approveDeptId = userStore.currentDeptId |
| | | |
| | | |
| | | // 加载部门选项,并在加载完成后设置部门名称 |
| | | getProductOptions(); |
| | | if (operationType.value === 'edit') { |
| | |
| | | if (res.data && res.data.approveUserIds) { |
| | | const userIds = res.data.approveUserIds.split(',') |
| | | approverNodes.value = userIds.map((userId, idx) => ({ |
| | | id: idx + 1, |
| | | id: idx + 1, |
| | | userId: parseInt(userId.trim()) |
| | | })) |
| | | nextApproverId = userIds.length + 1 |
| | |
| | | productOptions.value = res.data; |
| | | // 如果已有部门ID,自动设置部门名称(用于验证) |
| | | if (form.value.approveDeptId && productOptions.value.length > 0) { |
| | | const matchedDept = productOptions.value.find(dept => |
| | | dept.deptId == form.value.approveDeptId || |
| | | const matchedDept = productOptions.value.find(dept => |
| | | dept.deptId == form.value.approveDeptId || |
| | | String(dept.deptId) === String(form.value.approveDeptId) |
| | | ); |
| | | if (matchedDept) { |
| | |
| | | if (children && children.length > 0) { |
| | | newItem.children = convertIdToValue(children); |
| | | } |
| | | |
| | | |
| | | return newItem; |
| | | }); |
| | | } |
| | |
| | | |
| | | <style scoped> |
| | | |
| | | </style> |
| | | </style> |
| | |
| | | <el-tab-pane label="报价审批" name="6"></el-tab-pane> |
| | | <el-tab-pane label="发货审批" name="7"></el-tab-pane> |
| | | </el-tabs> |
| | | |
| | | |
| | | <div class="search_form"> |
| | | <div> |
| | | <span class="search_title">流程编号:</span> |
| | |
| | | const isReimburseType = currentApproveType.value === 4; // 报销管理 |
| | | const isQuotationType = currentApproveType.value === 6; // 报价审批 |
| | | const isPurchaseType = currentApproveType.value === 5; // 采购审批 |
| | | |
| | | |
| | | // 基础列配置 |
| | | const baseColumns = [ |
| | | { |
| | |
| | | width: 220 |
| | | }, |
| | | { |
| | | label: isQuotationType ? "报价单号" : isPurchaseType ? "采购合同号" : "审批事由", |
| | | label: isQuotationType ? "报价单号" : isPurchaseType ? "采购单号" : "审批事由", |
| | | prop: "approveReason", |
| | | }, |
| | | { |
| | |
| | | width: 120 |
| | | } |
| | | ]; |
| | | |
| | | |
| | | // 金额列(仅报销管理显示) |
| | | if (isReimburseType) { |
| | | baseColumns.push({ |
| | |
| | | width: 120 |
| | | }); |
| | | } |
| | | |
| | | |
| | | // 日期列(根据类型动态配置) |
| | | baseColumns.push( |
| | | { |
| | |
| | | width: 120 |
| | | } |
| | | ); |
| | | |
| | | |
| | | // 当前审批人列 |
| | | baseColumns.push({ |
| | | label: "当前审批人", |
| | | prop: "approveUserCurrentName", |
| | | width: 120 |
| | | }); |
| | | |
| | | |
| | | // 操作列 |
| | | const actionOperations = [ |
| | | { |
| | |
| | | width: 230, |
| | | operation: actionOperations, |
| | | }); |
| | | |
| | | |
| | | return baseColumns; |
| | | }); |
| | | const tableData = ref([]); |
| | |
| | | // 根据URL参数设置标签页和查询条件 |
| | | const approveType = route.query.approveType; |
| | | const approveId = route.query.approveId; |
| | | |
| | | |
| | | if (approveType) { |
| | | // 设置标签页(approveType 对应 activeTab 的 name) |
| | | activeTab.value = String(approveType); |
| | | } |
| | | |
| | | |
| | | if (approveId) { |
| | | // 设置流程编号查询条件 |
| | | searchForm.value.approveId = String(approveId); |
| | | } |
| | | |
| | | |
| | | // 查询列表 |
| | | getList(); |
| | | }); |
| | |
| | | <el-input v-model="searchForm.supplierName" placeholder="请输入" clearable prefix-icon="Search" |
| | | @change="handleQuery" /> |
| | | </el-form-item> |
| | | <el-form-item label="采购合同号:"> |
| | | <el-form-item label="采购单号:"> |
| | | <el-input |
| | | v-model="searchForm.purchaseContractNumber" |
| | | style="width: 240px" |
| | |
| | | :prefix-icon="Search" |
| | | /> |
| | | </el-form-item> |
| | | <el-form-item label="销售合同号:"> |
| | | <el-form-item label="销售单号:"> |
| | | <el-input v-model="searchForm.salesContractNo" placeholder="请输入" clearable prefix-icon="Search" |
| | | @change="handleQuery" /> |
| | | </el-form-item> |
| | |
| | | </el-table-column> |
| | | <el-table-column align="center" label="序号" type="index" width="60" /> |
| | | <el-table-column |
| | | label="采购合同号" |
| | | label="采购单号" |
| | | prop="purchaseContractNumber" |
| | | width="200" |
| | | show-overflow-tooltip |
| | | /> |
| | | <el-table-column |
| | | label="销售合同号" |
| | | label="销售单号" |
| | | prop="salesContractNo" |
| | | width="200" |
| | | show-overflow-tooltip |
| | |
| | | // 移除文件 |
| | | function handleRemove(file) { |
| | | console.log("handleRemove", file.id); |
| | | if (file.size > 1024 * 1024 * 10) { |
| | | if (file.size > 1024 * 1024 * 10) { |
| | | // 仅前端清理,不调用删除接口和提示 |
| | | return; |
| | | return; |
| | | } |
| | | if (operationType.value === "edit") { |
| | | let ids = []; |
| | |
| | | }; |
| | | // 审批通过方法 |
| | | const approvePurchase = (row) => { |
| | | ElMessageBox.confirm(`确认通过采购合同号为 ${row.purchaseContractNumber} 的审批?`, '审批确认', { |
| | | ElMessageBox.confirm(`确认通过采购单号为 ${row.purchaseContractNumber} 的审批?`, '审批确认', { |
| | | confirmButtonText: '确认', |
| | | cancelButtonText: '取消', |
| | | type: 'warning', |
| | |
| | | |
| | | // 审批拒绝方法 |
| | | const rejectPurchase = (row) => { |
| | | ElMessageBox.confirm(`确认拒绝采购合同号为 ${row.purchaseContractNumber} 的审批?`, '审批确认', { |
| | | ElMessageBox.confirm(`确认拒绝采购单号为 ${row.purchaseContractNumber} 的审批?`, '审批确认', { |
| | | confirmButtonText: '确认', |
| | | cancelButtonText: '取消', |
| | | type: 'warning', |
| | |
| | | if (field === 'taxInclusiveTotalPrice') { |
| | | // 已知含税总价和数量,反算含税单价 |
| | | if (productForm.value.quantity) { |
| | | productForm.value.taxInclusiveUnitPrice = |
| | | productForm.value.taxInclusiveUnitPrice = |
| | | (Number(productForm.value.taxInclusiveTotalPrice) / Number(productForm.value.quantity)).toFixed(2); |
| | | } |
| | | // 已知含税总价和含税单价,反算数量 |
| | | else if (productForm.value.taxInclusiveUnitPrice) { |
| | | productForm.value.quantity = |
| | | productForm.value.quantity = |
| | | (Number(productForm.value.taxInclusiveTotalPrice) / Number(productForm.value.taxInclusiveUnitPrice)).toFixed(2); |
| | | } |
| | | // 反算不含税总价 |
| | | productForm.value.taxExclusiveTotalPrice = |
| | | productForm.value.taxExclusiveTotalPrice = |
| | | (Number(productForm.value.taxInclusiveTotalPrice) / (1 + taxRate / 100)).toFixed(2); |
| | | } else if (field === 'taxExclusiveTotalPrice') { |
| | | // 反算含税总价 |
| | | productForm.value.taxInclusiveTotalPrice = |
| | | productForm.value.taxInclusiveTotalPrice = |
| | | (Number(productForm.value.taxExclusiveTotalPrice) * (1 + taxRate / 100)).toFixed(2); |
| | | // 已知数量,反算含税单价 |
| | | if (productForm.value.quantity) { |
| | | productForm.value.taxInclusiveUnitPrice = |
| | | productForm.value.taxInclusiveUnitPrice = |
| | | (Number(productForm.value.taxInclusiveTotalPrice) / Number(productForm.value.quantity)).toFixed(2); |
| | | } |
| | | // 已知含税单价,反算数量 |
| | | else if (productForm.value.taxInclusiveUnitPrice) { |
| | | productForm.value.quantity = |
| | | productForm.value.quantity = |
| | | (Number(productForm.value.taxInclusiveTotalPrice) / Number(productForm.value.taxInclusiveUnitPrice)).toFixed(2); |
| | | } |
| | | } |
| | |
| | | // 显示二维码 |
| | | const showQRCode = async (row) => { |
| | | try { |
| | | // 构建二维码内容,只包含采购合同号(纯文本) |
| | | // 构建二维码内容,只包含采购单号(纯文本) |
| | | const qrContent = row.purchaseContractNumber || ''; |
| | | // 检查内容是否为空 |
| | | if (!qrContent || qrContent.trim() === '') { |
| | | proxy.$modal.msgWarning("该行没有采购合同号,无法生成二维码"); |
| | | proxy.$modal.msgWarning("该行没有采购单号,无法生成二维码"); |
| | | return; |
| | | } |
| | | qrCodeUrl.value = await QRCode.toDataURL(qrContent, { |
| | |
| | | proxy.$modal.msgWarning("二维码未生成"); |
| | | return; |
| | | } |
| | | |
| | | |
| | | const a = document.createElement('a'); |
| | | a.href = qrCodeUrl.value; |
| | | a.download = `采购合同号二维码_${new Date().getTime()}.png`; |
| | | a.download = `采购单号二维码_${new Date().getTime()}.png`; |
| | | document.body.appendChild(a); |
| | | a.click(); |
| | | document.body.removeChild(a); |
| | |
| | | scanRemark: "", |
| | | }); |
| | | const scanAddRules = { |
| | | purchaseContractNumber: [{ required: true, message: "请输入采购合同号", trigger: "blur" }], |
| | | purchaseContractNumber: [{ required: true, message: "请输入采购单号", trigger: "blur" }], |
| | | supplierName: [{ required: true, message: "请输入供应商名称", trigger: "blur" }], |
| | | projectName: [{ required: true, message: "请输入项目名称", trigger: "blur" }], |
| | | }; |
| | |
| | | // 解析扫码内容(模拟解析二维码数据) |
| | | const parseScanContent = (content) => { |
| | | if (!content) return; |
| | | |
| | | |
| | | // 模拟解析二维码内容,这里可以根据实际需求调整解析逻辑 |
| | | // 假设扫码内容格式为:合同号|供应商|项目|金额|付款方式 |
| | | const parts = content.split('|'); |
| | |
| | | remark: scanAddForm.scanRemark, |
| | | type: 2 |
| | | }; |
| | | |
| | | |
| | | // 模拟新增成功 |
| | | proxy.$modal.msgSuccess("扫码新增成功!"); |
| | | closeScanAddDialog(); |
| | | |
| | | |
| | | // 可以选择是否刷新列表 |
| | | // getList(); |
| | | } |
| | |
| | | <div class="app-container"> |
| | | <div class="search_form"> |
| | | <div> |
| | | <span class="search_title">销售合同号:</span> |
| | | <span class="search_title">销售单号:</span> |
| | | <el-input |
| | | v-model="searchForm.salesContractNo" |
| | | style="width: 240px" |
| | | placeholder="请输入销售合同号搜索" |
| | | placeholder="请输入销售单号搜索" |
| | | @change="handleQuery" |
| | | clearable |
| | | :prefix-icon="Search" |
| | |
| | | }, |
| | | }, |
| | | { |
| | | label: "销售合同号", |
| | | label: "销售单号", |
| | | prop: "salesContractNo", |
| | | width: 170 |
| | | }, |
| | |
| | | <el-table-column prop="customerName" label="客户名称" min-width="120" show-overflow-tooltip /> |
| | | <el-table-column prop="productName" label="产品名称" min-width="120" show-overflow-tooltip /> |
| | | <el-table-column prop="specificationModel" label="规格型号" min-width="140" show-overflow-tooltip /> |
| | | <el-table-column prop="salesContractNo" label="销售合同号" min-width="140" show-overflow-tooltip /> |
| | | <el-table-column prop="salesContractNo" label="销售单号" min-width="140" show-overflow-tooltip /> |
| | | <el-table-column prop="shippingNo" label="发货单号" min-width="130" show-overflow-tooltip /> |
| | | <el-table-column prop="shippingDate" label="发货日期" width="110" align="center" /> |
| | | <el-table-column prop="outboundAmount" label="出库金额" width="110" align="right"> |
| | |
| | | min-width="140" |
| | | show-overflow-tooltip /> |
| | | <el-table-column prop="salesContractNo" |
| | | label="销售合同号" |
| | | label="销售单号" |
| | | min-width="140" |
| | | show-overflow-tooltip /> |
| | | <el-table-column prop="shippingNo" |
| | |
| | | > |
| | | <el-row :gutter="30"> |
| | | <el-col :span="12"> |
| | | <el-form-item label="采购合同号:" prop="purchaseLedgerNo"> |
| | | <el-form-item label="采购单号:" prop="purchaseLedgerNo"> |
| | | <el-input v-model="form.purchaseLedgerNo" disabled placeholder="多合同批量处理(具体合同号见产品列表)" /> |
| | | </el-form-item> |
| | | </el-col> |
| | | <el-col :span="12"> |
| | | <el-form-item label="销售合同号:" prop="salesContractNo"> |
| | | <el-form-item label="销售单号:" prop="salesContractNo"> |
| | | <el-input |
| | | v-model="form.salesContractNo" |
| | | placeholder="自动填充" |
| | |
| | | /> |
| | | </el-form-item> |
| | | </el-col> |
| | | |
| | | |
| | | </el-row> |
| | | <el-form-item label="产品信息:"> </el-form-item> |
| | | <el-table |
| | |
| | | /> |
| | | <el-table-column label="本次开票数" prop="ticketsNum" width="180"> |
| | | <template #default="scope"> |
| | | <el-input-number |
| | | :step="0.1" |
| | | :min="0" |
| | | :max="scope.row.tempFutureTickets || 0" |
| | | <el-input-number |
| | | :step="0.1" |
| | | :min="0" |
| | | :max="scope.row.tempFutureTickets || 0" |
| | | style="width: 100%" |
| | | :precision="2" |
| | | v-model="scope.row.ticketsNum" |
| | |
| | | width="180" |
| | | > |
| | | <template #default="scope"> |
| | | <el-input-number |
| | | :step="0.01" |
| | | :min="0" |
| | | <el-input-number |
| | | :step="0.01" |
| | | :min="0" |
| | | style="width: 100%" |
| | | :precision="2" |
| | | v-model="scope.row.ticketsAmount" |
| | |
| | | const formRef = ref(); |
| | | const { proxy } = getCurrentInstance(); |
| | | const { form } = useFormData({ |
| | | purchaseLedgerNo: undefined, // 采购合同号 |
| | | salesContractNo: undefined, // 销售合同号 |
| | | purchaseLedgerNo: undefined, // 采购单号 |
| | | salesContractNo: undefined, // 销售单号 |
| | | supplierName: undefined, // 供应商名称 |
| | | projectName: undefined, // 项目名称 |
| | | invoiceNumber: undefined, // 发票号 |
| | |
| | | const isSameSupplier = selectedRows.every(row => |
| | | row.supplierName === firstRow.supplierName |
| | | ); |
| | | |
| | | |
| | | if (!isSameSupplier) { |
| | | proxy.$modal.msgError("请选择相同供应商名称的合同"); |
| | | return; |
| | | } |
| | | |
| | | // 允许不同的采购合同号批量处理,无需检查重复 |
| | | |
| | | |
| | | // 允许不同的采购单号批量处理,无需检查重复 |
| | | |
| | | // 清空表单数据 |
| | | Object.keys(form).forEach(key => { |
| | | if (key !== 'productData') { |
| | |
| | | } |
| | | }); |
| | | form.productData = []; |
| | | |
| | | |
| | | // 加载所有选中合同的产品数据 |
| | | const promises = selectedRows.map(row => |
| | | getInfo({ id: row.id }) |
| | | ); |
| | | |
| | | |
| | | Promise.all(promises).then(results => { |
| | | // 合并所有合同的产品数据,并为每个产品添加对应的合同信息 |
| | | const allProductData = []; |
| | |
| | | allProductData.push({ |
| | | ...item, |
| | | purchaseLedgerId: contractId, // 添加合同ID用于筛选 |
| | | purchaseLedgerNo: contract.purchaseContractNumber, // 添加采购合同号 |
| | | purchaseLedgerNo: contract.purchaseContractNumber, // 添加采购单号 |
| | | supplierName: contract.supplierName, // 添加供应商名称 |
| | | projectName: contract.projectName // 添加项目名称 |
| | | // 保留产品本身的id,不覆盖 |
| | |
| | | }); |
| | | } |
| | | }); |
| | | |
| | | // 设置表单数据(使用第一个合同的基本信息,采购合同号留空) |
| | | form.purchaseLedgerNo = ""; // 采购合同号留空,因为会在产品表格中分别显示 |
| | | |
| | | // 设置表单数据(使用第一个合同的基本信息,采购单号留空) |
| | | form.purchaseLedgerNo = ""; // 采购单号留空,因为会在产品表格中分别显示 |
| | | form.invoiceNumber = ""; |
| | | form.entryDate = dayjs().format("YYYY-MM-DD"); |
| | | form.enterDate = dayjs().format("YYYY-MM-DD"); |
| | |
| | | // 保留录入人信息 |
| | | form.issUerId = userStore.id; |
| | | form.issUer = userStore.nickName; |
| | | |
| | | |
| | | // 设置产品数据,并初始化开票数量和金额 |
| | | allProductData.forEach(item => { |
| | | // 保存"原始未来票数/金额"(用于校验与计算) |
| | |
| | | ); |
| | | } |
| | | }); |
| | | |
| | | |
| | | form.productData = allProductData; |
| | | |
| | | |
| | | // 计算发票金额:所有产品的本次开票金额之和(新增默认 0) |
| | | const totalAmount = allProductData.reduce((sum, item) => { |
| | | return sum + (Number(item.ticketsAmount) || 0); |
| | | }, 0); |
| | | form.invoiceAmount = Number(totalAmount.toFixed(2)); |
| | | |
| | | |
| | | // 存储选中的合同数据 |
| | | selectedContracts.value = selectedRows; |
| | | }); |
| | |
| | | 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.supplierName = data.supplierName; |
| | | form.entryDate = data.entryDate; |
| | | form.enterDate = data.enterDate || dayjs().format("YYYY-MM-DD"); |
| | | |
| | | |
| | | // 编辑时也需要初始化产品数据的 tempFutureTickets 和 tempFutureTicketsAmount |
| | | // 同时为每个产品添加合同号等信息 |
| | | const contractNumber = data.purchaseContractNumber || data.purchaseLedgerNo || ""; |
| | |
| | | item.tempFutureTicketsAmount = Number( |
| | | item.futureTicketsAmount !== undefined ? item.futureTicketsAmount : (item.taxInclusiveTotalPrice || 0) |
| | | ); |
| | | |
| | | |
| | | // 确保每个产品都有合同号,用于显示在"所属合同"列 |
| | | if (!item.purchaseLedgerNo) { |
| | | item.purchaseLedgerNo = contractNumber; |
| | | } |
| | | }); |
| | | } |
| | | |
| | | |
| | | form.productData = data.productData || []; |
| | | |
| | | |
| | | // 编辑模式下,根据产品数据中的本次开票金额自动计算发票金额 |
| | | calculateinvoiceAmount(); |
| | | } |
| | |
| | | // 判断产品是否可以继续来票操作:如果未来票数和未来票金额都为0或小于等于0,则禁用 |
| | | const isProductDisabled = (row) => { |
| | | // 优先使用 tempFutureTickets(原始未来票数),如果没有则使用 futureTickets |
| | | const futureTickets = Number(row.tempFutureTickets !== undefined |
| | | ? row.tempFutureTickets |
| | | const futureTickets = Number(row.tempFutureTickets !== undefined |
| | | ? row.tempFutureTickets |
| | | : (row.futureTickets !== undefined ? row.futureTickets : 0)); |
| | | |
| | | |
| | | // 优先使用 tempFutureTicketsAmount(原始未来票金额),如果没有则使用 futureTicketsAmount |
| | | const futureAmount = Number(row.tempFutureTicketsAmount !== undefined |
| | | ? row.tempFutureTicketsAmount |
| | | const futureAmount = Number(row.tempFutureTicketsAmount !== undefined |
| | | ? row.tempFutureTicketsAmount |
| | | : (row.futureTicketsAmount !== undefined ? row.futureTicketsAmount : 0)); |
| | | |
| | | |
| | | // 只有当未来票数和未来票金额都为0或小于等于0时,才禁用 |
| | | return futureTickets <= 0 && futureAmount <= 0; |
| | | }; |
| | |
| | | if (!modalOptions.value || typeof modalOptions.value !== 'object') { |
| | | modalOptions.value = {}; |
| | | } |
| | | |
| | | |
| | | // 根据操作类型和选中数据设置标题 |
| | | if (Array.isArray(selectedRows) && selectedRows.length > 1) { |
| | | // 批量操作 |
| | |
| | | modalOptions.value.title = "来票登记"; // 默认标题 |
| | | } |
| | | } |
| | | |
| | | |
| | | visible.value = true; |
| | | |
| | | |
| | | // 如果是单个操作,获取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 contractProductData = form.productData.filter(item => |
| | | item.purchaseLedgerId === contract.id |
| | | ); |
| | | |
| | | |
| | | // 为每个采购合同创建独立的对象 |
| | | return { |
| | | // 基础表单数据 |
| | |
| | | enterDate: form.enterDate, |
| | | issUerId: form.issUerId, // 录入人id |
| | | issUer: form.issUer, // 录入人 |
| | | |
| | | |
| | | // 合同实际信息 |
| | | purchaseLedgerId: contract.id, // 使用id作为字段名,值为purchaseLedgerId |
| | | purchaseContractNumber: contract.purchaseContractNumber, // 使用实际的采购合同号 |
| | | salesContractNo: contract.salesContractNo, // 使用实际的销售合同号 |
| | | 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) => { |
| | |
| | | enterDate: form.enterDate, |
| | | issUerId: form.issUerId, // 录入人id |
| | | issUer: form.issUer, // 录入人 |
| | | |
| | | |
| | | // 合同实际信息 |
| | | purchaseLedgerId: singleContract.id, // 使用id作为字段名,值为purchaseLedgerId |
| | | purchaseContractNumber: singleContract.purchaseContractNumber, // 使用实际的采购合同号 |
| | | salesContractNo: singleContract.salesContractNo, // 使用实际的销售合同号 |
| | | 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(singleFormArray).then((res) => { |
| | | modalLoading.value = false; |
| | |
| | | /> |
| | | </el-form-item> |
| | | |
| | | <el-form-item label="销售合同号"> |
| | | <el-form-item label="销售单号"> |
| | | <el-input |
| | | v-model="filters.salesContractNo" |
| | | placeholder="请输入销售合同号" |
| | | placeholder="请输入销售单号" |
| | | clearable |
| | | /> |
| | | </el-form-item> |
| | |
| | | width:150 |
| | | }, |
| | | { |
| | | label: "销售合同号", |
| | | label: "销售单号", |
| | | prop: "salesContractNo", |
| | | width:150 |
| | | }, |
| | |
| | | size="small" |
| | | > |
| | | <el-table-column type="index" label="序号" width="50" align="center"/> |
| | | <el-table-column label="采购合同号" prop="purchaseContractNumber" show-overflow-tooltip /> |
| | | <el-table-column label="销售合同号" prop="salesContractNo" show-overflow-tooltip /> |
| | | <el-table-column label="采购单号" prop="purchaseContractNumber" show-overflow-tooltip /> |
| | | <el-table-column label="销售单号" prop="salesContractNo" show-overflow-tooltip /> |
| | | <el-table-column label="供应商名称" prop="supplierName" show-overflow-tooltip /> |
| | | <el-table-column |
| | | label="产品大类" |
| | |
| | | slot: "expand", |
| | | }, |
| | | { |
| | | label: "采购合同号", |
| | | label: "采购单号", |
| | | prop: "purchaseContractNumber", |
| | | width:160 |
| | | }, |
| | | { |
| | | label: "销售合同号", |
| | | label: "销售单号", |
| | | prop: "salesContractNo", |
| | | width:160 |
| | | }, |
| | |
| | | <template> |
| | | <div class="app-container"> |
| | | <el-form :model="searchForm" :inline="true"> |
| | | <el-form-item label="采购合同号"> |
| | | <el-form-item label="采购单号"> |
| | | <el-input |
| | | v-model="searchForm.purchaseContractNumber" |
| | | style="width: 240px" |
| | | placeholder="输入采购合同号搜索" |
| | | placeholder="输入采购单号搜索" |
| | | @change="handleQuery" |
| | | clearable |
| | | :prefix-icon="Search" |
| | |
| | | const isShowSummarySon = ref(true); |
| | | const tableColumn = ref([ |
| | | { |
| | | label: "采购合同号", |
| | | label: "采购单号", |
| | | prop: "purchaseContractNumber", |
| | | }, |
| | | { |
| | |
| | | width: 110, |
| | | }, |
| | | { |
| | | label: "采购合同号", |
| | | label: "采购单号", |
| | | prop: "purchaseContractNumber", |
| | | width: 150, |
| | | }, |
| | |
| | | <el-form :model="form"> |
| | | <el-row :gutter="20"> |
| | | <el-col :span="12"> |
| | | <el-form-item label="采购合同号:"> |
| | | <el-form-item label="采购单号:"> |
| | | <el-tag size="large">{{ form.purchaseContractNumber }}</el-tag> |
| | | </el-form-item> |
| | | </el-col> |
| | | <el-col :span="12"> |
| | | <el-form-item label="销售合同号:"> |
| | | <el-form-item label="销售单号:"> |
| | | <el-text>{{ form.salesContractNo }}</el-text> |
| | | </el-form-item> |
| | | </el-col> |
| | |
| | | |
| | | const { form, resetForm } = useFormData({ |
| | | id: undefined, |
| | | purchaseContractNumber: undefined, // 采购合同号 |
| | | salesContractNo: undefined, // 销售合同号 |
| | | purchaseContractNumber: undefined, // 采购单号 |
| | | salesContractNo: undefined, // 销售单号 |
| | | createdAt: undefined, // 创建时间 |
| | | invoiceNumber: undefined, // 发票号 |
| | | ticketsNum: undefined, // 来票数 |
| | |
| | | proxy.$modal.msgWarning("含税单价不能为零或未定义"); |
| | | return; |
| | | } |
| | | |
| | | |
| | | // 检查来票数不能大于(原始已来票数 + 未来票数) |
| | | const maxNum = maxTicketsNum.value; |
| | | if (Number(form.ticketsNum) > maxNum) { |
| | |
| | | form.ticketsNum = maxNum; |
| | | return; |
| | | } |
| | | |
| | | |
| | | // 计算本次新增的来票数(当前来票数 - 原始已来票数) |
| | | const newTicketsNum = Number(form.ticketsNum) - Number(originalTicketsNum.value); |
| | | |
| | | |
| | | // 如果新增的来票数大于未来票数,则限制 |
| | | if (newTicketsNum > Number(temFutureTickets.value)) { |
| | | proxy.$modal.msgWarning("本次新增来票数不得大于未来票数"); |
| | |
| | | |
| | | // 计算最大可填写金额 = (原始已来票数 + 未来票数)* 含税单价 |
| | | const maxAmount = maxTicketsNum.value * Number(form.taxInclusiveUnitPrice); |
| | | |
| | | |
| | | if (Number(val) > maxAmount) { |
| | | proxy.$modal.msgWarning(`本次来票金额不得大于${maxAmount.toFixed(2)}元`); |
| | | form.ticketsAmount = maxAmount.toFixed(2); |
| | |
| | | |
| | | // 确保所有数值都转换为数字类型进行计算 |
| | | const ticketsNum = Number(val) / Number(form.taxInclusiveUnitPrice); |
| | | |
| | | |
| | | // 检查来票数不能大于最大值 |
| | | if (ticketsNum > maxTicketsNum.value) { |
| | | proxy.$modal.msgWarning(`来票数不能大于${maxTicketsNum.value}`); |
| | |
| | | form.ticketsAmount = maxAmount.toFixed(2); |
| | | return; |
| | | } |
| | | |
| | | |
| | | form.ticketsNum = Number(ticketsNum.toFixed(2)); |
| | | |
| | | |
| | | // 计算未来票数 |
| | | const newTicketsNum = form.ticketsNum - originalTicketsNum.value; |
| | | const futureTickets = Number(temFutureTickets.value) - newTicketsNum; |
| | |
| | | <template> |
| | | <div class="app-container"> |
| | | <el-form :model="filters" :inline="true"> |
| | | <el-form-item label="采购合同号"> |
| | | <el-form-item label="采购单号"> |
| | | <el-input |
| | | v-model="filters.purchaseContractNumber" |
| | | style="width: 240px" |
| | |
| | | </template> |
| | | </PIMTable> |
| | | </div> |
| | | <FileListDialog |
| | | ref="fileListRef" |
| | | <FileListDialog |
| | | ref="fileListRef" |
| | | v-model="fileListDialogVisible" |
| | | title="附件列表" |
| | | :showUploadButton="true" |
| | |
| | | } = usePaginationApi( |
| | | productRecordPage, |
| | | { |
| | | purchaseContractNumber: undefined, // 采购合同号 |
| | | purchaseContractNumber: undefined, // 采购单号 |
| | | supplierName: undefined, // 供应商 |
| | | createdAt: [], // 来票日期 |
| | | }, |
| | | [ |
| | | { |
| | | label: "采购合同号", |
| | | label: "采购单号", |
| | | prop: "purchaseContractNumber", |
| | | width: 150, |
| | | }, |
| | | { |
| | | label: "销售合同号", |
| | | label: "销售单号", |
| | | prop: "salesContractNo", |
| | | width: 150, |
| | | }, |
| | |
| | | proxy.$modal.msgWarning("缺少登记ID,无法保存附件"); |
| | | return; |
| | | } |
| | | |
| | | |
| | | return new Promise((resolve) => { |
| | | // 创建一个隐藏的文件输入元素 |
| | | const input = document.createElement('input'); |
| | |
| | | resolve(null); |
| | | return; |
| | | } |
| | | |
| | | |
| | | try { |
| | | // 使用 FormData 上传文件 |
| | | const formData = new FormData(); |
| | | formData.append('file', file); |
| | | formData.append('type', '4'); // type 参数,用户未指定具体值,先传空字符串 |
| | | formData.append('id', currentRowId.value); // 当前行的 id |
| | | |
| | | |
| | | const uploadRes = await request({ |
| | | url: '/file/uploadByCommon', |
| | | method: 'post', |
| | |
| | | Authorization: `Bearer ${getToken()}` |
| | | } |
| | | }); |
| | | |
| | | |
| | | if (uploadRes.code === 200) { |
| | | proxy.$modal.msgSuccess("附件上传成功"); |
| | | |
| | | |
| | | // 刷新列表获取最新数据 |
| | | await new Promise((resolveRefresh) => { |
| | | // 调用 API 获取最新列表数据 |
| | |
| | | // 更新数据列表 |
| | | dataList.value = data.records; |
| | | pagination.total = data.total; |
| | | |
| | | |
| | | // 从外部数据获取 commonFiles |
| | | const currentRow = dataList.value.find(row => row.id === currentRowId.value); |
| | | if (currentRow && fileListRef.value) { |
| | |
| | | resolveRefresh(); |
| | | }); |
| | | }); |
| | | |
| | | |
| | | resolve({ |
| | | name: uploadRes.data?.originalName || file.name, |
| | | url: uploadRes.data?.tempPath || uploadRes.data?.url, |
| | |
| | | document.body.removeChild(input); |
| | | } |
| | | }; |
| | | |
| | | |
| | | document.body.appendChild(input); |
| | | input.click(); |
| | | }); |
| | |
| | | try { |
| | | await delCommonFile([file.id]); |
| | | proxy.$modal.msgSuccess("删除成功"); |
| | | |
| | | |
| | | // 刷新列表获取最新数据 |
| | | await new Promise((resolveRefresh) => { |
| | | // 调用 API 获取最新列表数据 |
| | |
| | | // 更新数据列表 |
| | | dataList.value = data.records; |
| | | pagination.total = data.total; |
| | | |
| | | |
| | | // 从外部数据获取 commonFiles |
| | | const currentRow = dataList.value.find(row => row.id === currentRowId.value); |
| | | if (currentRow && fileListRef.value) { |
| | |
| | | resolveRefresh(); |
| | | }); |
| | | }); |
| | | |
| | | |
| | | return true; |
| | | } catch (error) { |
| | | proxy.$modal.msgError("删除失败"); |
| | |
| | | prop="availableQuality" /> |
| | | <el-table-column label="退货数量" |
| | | prop="returnQuality" /> |
| | | |
| | | |
| | | <el-table-column label="税率(%)" |
| | | prop="taxRate" /> |
| | | <el-table-column label="含税单价(元)" |
| | |
| | | width="100" |
| | | show-overflow-tooltip> |
| | | <template #default="scope"> |
| | | <el-tag |
| | | <el-tag |
| | | :type="getApprovalStatusType(scope.row.approvalStatus)" |
| | | size="small"> |
| | | {{ approvalStatusText[scope.row.approvalStatus] || '未知状态' }} |
| | |
| | | :value="item.templateName"> |
| | | <div style="display: flex; justify-content: space-between; align-items: center;"> |
| | | <span>{{ item.templateName }}</span> |
| | | <el-icon |
| | | <el-icon |
| | | v-if="item.id" |
| | | class="delete-icon" |
| | | @click.stop="handleDeleteTemplate(item)" |
| | |
| | | </el-row> |
| | | </el-form> |
| | | </FormDialog> |
| | | <FileListDialog |
| | | ref="fileListRef" |
| | | <FileListDialog |
| | | ref="fileListRef" |
| | | v-model="fileListDialogVisible" |
| | | title="附件列表" |
| | | /> |
| | |
| | | .filter(node => node.userId) |
| | | .map(node => node.userId) |
| | | .join(","); |
| | | |
| | | |
| | | let params = { |
| | | productData: proxy.HaveJson(productData.value), |
| | | supplierId: form.value.supplierId, |
| | |
| | | return; |
| | | } |
| | | } |
| | | |
| | | |
| | | await getTemplateList(); |
| | | operationType.value = type; |
| | | form.value = {}; |
| | |
| | | form.value.entryDate = getCurrentDate(); |
| | | |
| | | if (type === "add") { |
| | | // 新增时生成采购合同号 |
| | | // 新增时生成采购单号 |
| | | try { |
| | | const purchaseNoRes = await createPurchaseNo(); |
| | | if (purchaseNoRes?.data) { |
| | | form.value.purchaseContractNumber = purchaseNoRes.data; |
| | | } |
| | | } catch (error) { |
| | | console.error("生成采购合同号失败:", error); |
| | | proxy.$modal.msgWarning("生成采购合同号失败"); |
| | | console.error("生成采购单号失败:", error); |
| | | proxy.$modal.msgWarning("生成采购单号失败"); |
| | | } |
| | | } else if (type === "edit" && row?.id) { |
| | | // 编辑时加载数据 |
| | |
| | | return; |
| | | } |
| | | const approveUserIds = approverNodes.value.map(node => node.userId).join(","); |
| | | |
| | | |
| | | if (productData.value.length > 0) { |
| | | // 新增时,需要从每个产品对象中删除 id 字段 |
| | | let processedProductData = productData.value; |
| | |
| | | productForm.value = {}; |
| | | proxy.resetForm("productFormRef"); |
| | | productFormVisible.value = true; |
| | | |
| | | |
| | | // 先获取产品选项,确保数据加载完成 |
| | | await getProductOptions(); |
| | | |
| | | |
| | | // 等待 DOM 更新 |
| | | await nextTick(); |
| | | |
| | | |
| | | if (type === "edit") { |
| | | // 复制行数据 |
| | | productForm.value = { ...row }; |
| | | |
| | | |
| | | // 如果是从模板加载的数据,可能没有 productId 和 productModelId |
| | | // 需要根据 productCategory 和 specificationModel 来查找对应的 ID |
| | | if (!productForm.value.productId && productForm.value.productCategory) { |
| | |
| | | } |
| | | return null; |
| | | }; |
| | | |
| | | |
| | | const productId = findProductIdByCategory(productOptions.value, productForm.value.productCategory); |
| | | if (productId) { |
| | | productForm.value.productId = productId; |
| | | // 获取型号列表并等待完成 |
| | | const modelRes = await modelList({ id: productId }); |
| | | modelOptions.value = modelRes; |
| | | |
| | | |
| | | // 等待 DOM 更新 |
| | | await nextTick(); |
| | | |
| | | |
| | | // 根据 specificationModel 查找 productModelId |
| | | if (productForm.value.specificationModel && modelOptions.value.length > 0) { |
| | | const modelItem = modelOptions.value.find( |
| | |
| | | } else if (productForm.value.productId) { |
| | | // 如果有 productId,正常加载型号列表 |
| | | await getModels(productForm.value.productId); |
| | | |
| | | |
| | | // 等待 DOM 更新 |
| | | await nextTick(); |
| | | |
| | | |
| | | if (productForm.value.productModelId) { |
| | | getProductModel(productForm.value.productModelId); |
| | | } |
| | | } |
| | | |
| | | |
| | | // 最后再等待一次 DOM 更新,确保所有数据都已设置 |
| | | await nextTick(); |
| | | } |
| | |
| | | proxy.$modal.msgWarning("无法删除该模板"); |
| | | return; |
| | | } |
| | | |
| | | |
| | | try { |
| | | await ElMessageBox.confirm( |
| | | `确定要删除模板"${item.templateName}"吗?`, |
| | |
| | | type: "warning", |
| | | } |
| | | ); |
| | | |
| | | |
| | | const res = await delPurchaseTemplate([item.id]); |
| | | if (res && res.code === 200) { |
| | | ElMessage({ |
| | |
| | | display: flex; |
| | | align-items: center; |
| | | } |
| | | |
| | | |
| | | // 审批人节点容器样式 |
| | | .approver-nodes-container { |
| | | display: flex; |
| | |
| | | border-radius: 4px; |
| | | border: 1px solid #e4e7ed; |
| | | } |
| | | |
| | | |
| | | .approver-node-item { |
| | | flex: 0 0 calc(33.333% - 12px); |
| | | min-width: 200px; |
| | |
| | | border-radius: 4px; |
| | | border: 1px solid #dcdfe6; |
| | | transition: all 0.3s; |
| | | |
| | | |
| | | &:hover { |
| | | border-color: #409eff; |
| | | box-shadow: 0 2px 8px rgba(64, 158, 255, 0.1); |
| | | } |
| | | } |
| | | |
| | | |
| | | .approver-node-header { |
| | | display: flex; |
| | | justify-content: space-between; |
| | | align-items: center; |
| | | margin-bottom: 8px; |
| | | } |
| | | |
| | | |
| | | .approver-node-label { |
| | | font-size: 13px; |
| | | font-weight: 500; |
| | | color: #606266; |
| | | } |
| | | |
| | | |
| | | @media (max-width: 1200px) { |
| | | .approver-node-item { |
| | | flex: 0 0 calc(50% - 8px); |
| | | } |
| | | } |
| | | |
| | | |
| | | @media (max-width: 768px) { |
| | | .approver-node-item { |
| | | flex: 0 0 100%; |
| | | } |
| | | } |
| | | |
| | | |
| | | // 删除图标样式 |
| | | .delete-icon { |
| | | transition: all 0.3s; |
| | |
| | | </el-form-item> |
| | | |
| | | <el-form-item |
| | | label="采购合同号:" |
| | | label="采购单号:" |
| | | prop="purchaseLedgerId" |
| | | :rules="[ |
| | | { |
| | | required: true, |
| | | message: '请选择采购合同号', |
| | | message: '请选择采购单号', |
| | | trigger: 'change', |
| | | } |
| | | ]" |
| | |
| | | v-model="formState.incomeType" |
| | | placeholder="请选择" |
| | | clearable |
| | | |
| | | |
| | | > |
| | | <el-option :label="item.label" :value="item.value" v-for="(item,index) in payment_methods" :key="index" /> |
| | | </el-select> |
| | |
| | | border-radius: 50%; |
| | | margin-right: 8px; |
| | | } |
| | | </style> |
| | | </style> |
| | |
| | | <div class="app-container"> |
| | | <!-- 搜索过滤区 --> |
| | | <el-form :model="searchForm" :inline="true"> |
| | | <el-form-item label="采购合同号"> |
| | | <el-form-item label="采购单号"> |
| | | <el-input v-model="searchForm.purchaseContractNumber" placeholder="请输入" /> |
| | | </el-form-item> |
| | | <el-form-item label="供应商"> |
| | |
| | | <el-table :data="orderList" border v-loading="loading" height="calc(100vh - 12em)"> |
| | | <!-- 添加序号列 --> |
| | | <el-table-column align="center" label="序号" type="index" width="60" /> |
| | | <el-table-column prop="purchaseContractNumber" label="采购合同号" show-overflow-tooltip /> |
| | | <el-table-column prop="purchaseContractNumber" label="采购单号" show-overflow-tooltip /> |
| | | <el-table-column prop="supplierName" label="供应商" show-overflow-tooltip /> |
| | | <el-table-column label="付款状态"> |
| | | <template #default="scope"> |
| | |
| | | <!-- 确认收货对话框 --> |
| | | <FormDialog v-model="receiptDialogVisible" title="确认收货" :width="'70%'" @close="receiptDialogVisible = false" @confirm="submitReceipt" @cancel="receiptDialogVisible = false"> |
| | | <el-form :model="receiptForm" label-width="120px" ref="formRef"> |
| | | <el-form-item label="采购合同号"> |
| | | <el-form-item label="采购单号"> |
| | | <el-input v-model="receiptForm.purchaseContractNumber" disabled /> |
| | | </el-form-item> |
| | | <el-form-item label="异常原因"> |
| | |
| | | width: '120px', |
| | | }, |
| | | { |
| | | label: "销售合同号", |
| | | label: "销售单号", |
| | | prop: "salesContractNo", |
| | | width: '150px', |
| | | }, |
| | |
| | | width: 120, |
| | | }, |
| | | { |
| | | label: "销售合同号", |
| | | label: "销售单号", |
| | | prop: "salesContractNo", |
| | | width: 120, |
| | | }, |
| | |
| | | prop: "unit", |
| | | width: 120, |
| | | }, |
| | | |
| | | |
| | | { |
| | | label: "创建时间", |
| | | prop: "createTime", |
| | |
| | | > |
| | | <el-table-column type="selection" width="55" align="center" /> |
| | | <el-table-column label="序号" type="index" width="55" align="center" /> |
| | | <el-table-column label="销售合同号" prop="contractNo" width="160" /> |
| | | <el-table-column label="销售单号" prop="contractNo" width="160" /> |
| | | <el-table-column label="产品编号" prop="productCode" width="140" /> |
| | | <el-table-column label="产品型号" prop="productModel" width="140" /> |
| | | <el-table-column label="客户名称" prop="customerName" width="160" /> |
| | |
| | | > |
| | | <el-row> |
| | | <el-col :span="12"> |
| | | <el-form-item label="销售合同号" prop="contractNo"> |
| | | <el-form-item label="销售单号" prop="contractNo"> |
| | | <el-input |
| | | v-model="form.contractNo" |
| | | placeholder="请选择关联销售合同号" |
| | | placeholder="请选择关联销售单号" |
| | | /> |
| | | </el-form-item> |
| | | </el-col> |
| | |
| | | }, |
| | | rules: { |
| | | contractNo: [ |
| | | { required: true, message: "销售合同号不能为空", trigger: "blur" }, |
| | | { required: true, message: "销售单号不能为空", trigger: "blur" }, |
| | | ], |
| | | productCode: [ |
| | | { required: true, message: "产品编号不能为空", trigger: "blur" }, |
| | |
| | | }, |
| | | [ |
| | | { |
| | | label: "销售合同号", |
| | | label: "销售单号", |
| | | align: "center", |
| | | prop: "customerContractNo", |
| | | }, |
| | |
| | | </el-row> |
| | | <el-row v-if="!isQuotationApproval && !isPurchaseApproval"> |
| | | <el-col :span="24"> |
| | | <el-form-item :label="props.approveType == 5 ? '采购合同号:' : '审批事由:'" |
| | | <el-form-item :label="props.approveType == 5 ? '采购单号:' : '审批事由:'" |
| | | prop="approveReason"> |
| | | <el-input v-model="form.approveReason" |
| | | placeholder="请输入" |
| | |
| | | <template v-else> |
| | | <el-descriptions :column="2" |
| | | border> |
| | | <el-descriptions-item label="采购合同号">{{ currentPurchase.purchaseContractNumber }}</el-descriptions-item> |
| | | <el-descriptions-item label="采购单号">{{ currentPurchase.purchaseContractNumber }}</el-descriptions-item> |
| | | <el-descriptions-item label="供应商名称">{{ currentPurchase.supplierName }}</el-descriptions-item> |
| | | <el-descriptions-item label="项目名称">{{ currentPurchase.projectName }}</el-descriptions-item> |
| | | <el-descriptions-item label="销售合同号">{{ currentPurchase.salesContractNo }}</el-descriptions-item> |
| | | <el-descriptions-item label="销售单号">{{ currentPurchase.salesContractNo }}</el-descriptions-item> |
| | | <el-descriptions-item label="签订日期">{{ currentPurchase.executionDate }}</el-descriptions-item> |
| | | <el-descriptions-item label="录入日期">{{ currentPurchase.entryDate }}</el-descriptions-item> |
| | | <el-descriptions-item label="付款方式">{{ currentPurchase.paymentMethod }}</el-descriptions-item> |
| | |
| | | } |
| | | } |
| | | |
| | | // 采购审批:用审批事由字段承载的"采购合同号"去查采购详情 |
| | | // 采购审批:用审批事由字段承载的"采购单号"去查采购详情 |
| | | if (isPurchaseApproval.value) { |
| | | const purchaseContractNumber = row?.approveReason; |
| | | if (purchaseContractNumber) { |
| | |
| | | width: 200px; |
| | | height: 60px; |
| | | } |
| | | </style> |
| | | </style> |
| | |
| | | </el-row> |
| | | <el-row> |
| | | <el-col :span="24"> |
| | | <el-form-item :label="props.approveType == 5 ? '采购合同号:' : '审批事由:'" |
| | | <el-form-item :label="props.approveType == 5 ? '采购单号:' : '审批事由:'" |
| | | prop="approveReason"> |
| | | <el-input v-model="form.approveReason" |
| | | placeholder="请输入" |
| | |
| | | </script> |
| | | |
| | | <style scoped> |
| | | </style> |
| | | </style> |
| | |
| | | <div class="search_form"> |
| | | <el-form :inline="true" :model="searchForm"> |
| | | <el-form-item label="客户名称/合同号"> |
| | | <el-input v-model="searchForm.searchText" style="width: 240px" placeholder="输入客户名称/销售合同号搜索" |
| | | <el-input v-model="searchForm.searchText" style="width: 240px" placeholder="输入客户名称/销售单号搜索" |
| | | @change="handleQuery" clearable :prefix-icon="Search" /> |
| | | </el-form-item> |
| | | <el-form-item label="开票日期"> |
| | |
| | | :row-key="(row) => row.id" show-summary :summary-method="summarizeMainTable" height="calc(100vh - 18.5em)"> |
| | | <el-table-column align="center" type="selection" width="55" /> |
| | | <el-table-column align="center" label="序号" type="index" width="60" /> |
| | | <el-table-column label="销售合同号" prop="salesContractNo" show-overflow-tooltip width="180" /> |
| | | <el-table-column label="销售单号" prop="salesContractNo" show-overflow-tooltip width="180" /> |
| | | <el-table-column label="客户名称" prop="customerName" show-overflow-tooltip width="240" /> |
| | | <el-table-column label="产品大类" prop="productCategory" width="200" /> |
| | | <el-table-column label="规格型号" prop="specificationModel" width="160" show-overflow-tooltip /> |
| | |
| | | <el-form :model="form" label-width="140px" label-position="top" :rules="rules" ref="formRef"> |
| | | <el-row :gutter="30"> |
| | | <el-col :span="12"> |
| | | <el-form-item label="销售合同号:" prop="salesContractNo"> |
| | | <el-form-item label="销售单号:" prop="salesContractNo"> |
| | | <el-input v-model="form.salesContractNo" disabled></el-input> |
| | | </el-form-item> |
| | | </el-col> |
| | |
| | | if (!form.value.invoicePerson) { |
| | | form.value.invoicePerson = userStore.nickName; |
| | | } |
| | | |
| | | |
| | | // 计算发票金额最大值:noInvoiceAmount + invoiceAmount |
| | | const noInvoiceAmount = parseFloat(res.data.noInvoiceAmount || 0); |
| | | const invoiceAmount = parseFloat(res.data.invoiceAmount || 0); |
| | |
| | | <div class="flex justify-between"> |
| | | <div></div> |
| | | <div> |
| | | <el-button |
| | | type="primary" |
| | | @click="openForm" |
| | | <el-button |
| | | type="primary" |
| | | @click="openForm" |
| | | style="margin-bottom: 8px" |
| | | :disabled="!canInvoice" |
| | | > |
| | |
| | | </el-table-column> |
| | | <el-table-column align="center" label="序号" type="index" width="60" /> |
| | | <el-table-column |
| | | label="销售合同号" |
| | | label="销售单号" |
| | | prop="salesContractNo" |
| | | show-overflow-tooltip |
| | | /> |
| | |
| | | prop="contractAmount" |
| | | show-overflow-tooltip |
| | | :formatter="formattedNumber" |
| | | |
| | | |
| | | /> |
| | | <el-table-column |
| | | label="已开票金额(元)" |
| | |
| | | > |
| | | <el-row :gutter="30"> |
| | | <el-col :span="12"> |
| | | <el-form-item label="销售合同号:" prop="salesContractNo"> |
| | | <el-form-item label="销售单号:" prop="salesContractNo"> |
| | | <el-input v-model="form.salesContractNo" disabled placeholder="多合同批量处理(具体合同号见产品列表)"></el-input> |
| | | </el-form-item> |
| | | </el-col> |
| | |
| | | /> |
| | | </el-form-item> |
| | | </el-col> |
| | | |
| | | |
| | | </el-row> |
| | | <el-row> |
| | | <el-form-item label="产品信息:" prop="entryDate"> </el-form-item> |
| | |
| | | /> |
| | | <el-table-column label="本次开票数" prop="currentInvoiceNum" width="180"> |
| | | <template #default="scope"> |
| | | <el-input-number |
| | | :step="0.1" |
| | | :min="0" |
| | | <el-input-number |
| | | :step="0.1" |
| | | :min="0" |
| | | style="width: 100%" |
| | | :precision="2" |
| | | v-model="scope.row.currentInvoiceNum" |
| | |
| | | width="180" |
| | | > |
| | | <template #default="scope"> |
| | | <el-input-number |
| | | :step="0.01" |
| | | :min="0" |
| | | <el-input-number |
| | | :step="0.01" |
| | | :min="0" |
| | | style="width: 100%" |
| | | :precision="2" |
| | | v-model="scope.row.currentInvoiceAmount" |
| | |
| | | proxy.$modal.msgError("请至少选择一条合同"); |
| | | return; |
| | | } |
| | | |
| | | |
| | | // 检查所有选择的合同是否具有相同的客户名称 |
| | | const firstRow = selectedRows.value[0]; |
| | | const isSameCustomer = selectedRows.value.every(row => |
| | | row.customerName === firstRow.customerName |
| | | ); |
| | | |
| | | |
| | | if (!isSameCustomer) { |
| | | proxy.$modal.msgError("请选择相同客户名称的合同"); |
| | | return; |
| | | } |
| | | |
| | | // 允许不同的销售合同号批量处理,无需检查重复 |
| | | |
| | | |
| | | // 允许不同的销售单号批量处理,无需检查重复 |
| | | |
| | | form.value = {}; |
| | | productData.value = []; |
| | | |
| | | |
| | | // 加载所有选中合同的产品数据 |
| | | const promises = selectedRows.value.map(row => |
| | | getSalesLedgerWithProducts({ id: row.id }) |
| | | ); |
| | | |
| | | |
| | | Promise.all(promises).then(results => { |
| | | // 合并所有合同的产品数据,并为每个产品添加对应的合同信息 |
| | | const allProductData = []; |
| | |
| | | allProductData.push({ |
| | | ...item, |
| | | // id: contractId, // 明确设置合同ID |
| | | salesContractNo: contract.salesContractNo, // 添加销售合同号 |
| | | salesContractNo: contract.salesContractNo, // 添加销售单号 |
| | | customerName: contract.customerName, // 添加客户名称 |
| | | customerContractNo: contract.customerContractNo // 添加客户合同号 |
| | | }); |
| | | }); |
| | | } |
| | | }); |
| | | |
| | | // 设置表单数据(使用第一个合同的基本信息,销售合同号留空) |
| | | |
| | | // 设置表单数据(使用第一个合同的基本信息,销售单号留空) |
| | | form.value = { ...results[0] }; |
| | | form.value.createTime = dayjs().format("YYYY-MM-DD"); |
| | | form.value.issueDate = dayjs().format("YYYY-MM-DD"); |
| | | form.value.createUer = userStore.nickName; |
| | | form.value.selectedContractIds = selectedRows.value.map(row => row.id); // 存储所有选中的合同ID |
| | | form.value.salesContractNo = ""; // 销售合同号留空,因为会在产品表格中分别显示 |
| | | |
| | | form.value.salesContractNo = ""; // 销售单号留空,因为会在产品表格中分别显示 |
| | | |
| | | productData.value = allProductData; |
| | | |
| | | |
| | | // 对于不能开票的产品,将开票数和开票金额设置为0 |
| | | productData.value.forEach(item => { |
| | | if (isProductInvoiceDisabled(item)) { |
| | |
| | | item.currentInvoiceAmount = 0; |
| | | } |
| | | }); |
| | | |
| | | |
| | | dialogFormVisible.value = true; |
| | | console.log("productData.value ", productData.value); |
| | | }); |
| | |
| | | const contractProductData = productData.value.filter(item => |
| | | item.salesLedgerId === contract.id |
| | | ); |
| | | |
| | | // 为每个销售合同号创建独立的对象 |
| | | |
| | | // 为每个销售单号创建独立的对象 |
| | | return { |
| | | // 基础表单数据 |
| | | issueDate: form.value.issueDate, |
| | | createTime: form.value.createTime, |
| | | createUer: form.value.createUer, |
| | | invoiceNo: form.value.invoiceNo, |
| | | |
| | | |
| | | // 合同实际信息 |
| | | id: contract.id, // 使用id作为字段名,值为salesLedgerId |
| | | salesContractNo: contract.salesContractNo, // 使用实际的销售合同号 |
| | | salesContractNo: contract.salesContractNo, // 使用实际的销售单号 |
| | | customerName: contract.customerName, // 使用实际的客户名称 |
| | | customerId: contract.customerId, // 添加客户ID |
| | | customerContractNo: contract.customerContractNo, // 使用实际的客户合同号 |
| | | projectName: contract.projectName, // 使用实际的项目名称 |
| | | salesman: contract.salesman, // 使用实际的业务员 |
| | | |
| | | |
| | | // 产品数据 |
| | | productData: proxy.HaveJson(contractProductData), |
| | | |
| | | |
| | | // 批量标识 |
| | | isBatch: true |
| | | }; |
| | | }); |
| | | |
| | | |
| | | // 只调用一次接口,传递包含所有合同数据的数组 |
| | | invoiceRegistrationSave(batchData).then(() => { |
| | | proxy.$modal.msgSuccess("批量新增成功"); |
| | |
| | | createTime: form.value.createTime, |
| | | createUer: form.value.createUer, |
| | | invoiceNo: form.value.invoiceNo, |
| | | |
| | | |
| | | // 合同实际信息 |
| | | id: singleContract.id, // 使用id作为字段名,值为salesLedgerId |
| | | salesContractNo: singleContract.salesContractNo, // 使用实际的销售合同号 |
| | | salesContractNo: singleContract.salesContractNo, // 使用实际的销售单号 |
| | | customerName: singleContract.customerName, // 使用实际的客户名称 |
| | | customerId: singleContract.customerId, // 添加客户ID |
| | | customerContractNo: singleContract.customerContractNo, // 使用实际的客户合同号 |
| | | projectName: singleContract.projectName, // 使用实际的项目名称 |
| | | salesman: singleContract.salesman, // 使用实际的业务员 |
| | | |
| | | |
| | | // 产品数据 |
| | | productData: proxy.HaveJson(productData.value), |
| | | |
| | | |
| | | // 批量标识 |
| | | isBatch: false |
| | | } |
| | |
| | | </el-table-column> |
| | | <el-table-column align="center" label="序号" type="index" width="60" /> |
| | | <el-table-column |
| | | label="销售合同号" |
| | | label="销售单号" |
| | | prop="salesContractNo" |
| | | show-overflow-tooltip |
| | | width="240" |
| | |
| | | size="small" |
| | | > |
| | | <el-table-column type="index" label="序号" width="50" align="center"/> |
| | | <el-table-column label="销售合同号" prop="salesContractNo" show-overflow-tooltip /> |
| | | <el-table-column label="销售单号" prop="salesContractNo" show-overflow-tooltip /> |
| | | <el-table-column label="客户名称" prop="customerName" show-overflow-tooltip /> |
| | | <el-table-column |
| | | label="产品大类" |
| | |
| | | const { proxy } = getCurrentInstance(); |
| | | const tableColumn = ref([ |
| | | { |
| | | label: "销售合同号", |
| | | label: "销售单号", |
| | | prop: "salesContractNo", |
| | | width:240 |
| | | }, |
| | |
| | | <el-input v-model="searchForm.customerName" placeholder="请输入" clearable prefix-icon="Search" |
| | | @change="handleQuery" /> |
| | | </el-form-item> |
| | | <el-form-item label="销售合同号:"> |
| | | <el-form-item label="销售单号:"> |
| | | <el-input v-model="searchForm.salesContractNo" placeholder="请输入" clearable prefix-icon="Search" |
| | | @change="handleQuery" /> |
| | | </el-form-item> |
| | |
| | | <!--操作--> |
| | | <el-table-column Width="60px" label="操作" align="center"> |
| | | <template #default="scope"> |
| | | <el-button |
| | | link |
| | | <el-button |
| | | link |
| | | type="primary" |
| | | :disabled="!canShip(scope.row)" |
| | | @click="openDeliveryForm(scope.row)"> |
| | |
| | | </template> |
| | | </el-table-column> |
| | | <el-table-column align="center" label="序号" type="index" width="60" /> |
| | | <el-table-column label="销售合同号" prop="salesContractNo" width="180" show-overflow-tooltip /> |
| | | <el-table-column label="销售单号" prop="salesContractNo" width="180" show-overflow-tooltip /> |
| | | <el-table-column label="客户名称" prop="customerName" width="300" show-overflow-tooltip /> |
| | | <el-table-column label="业务员" prop="salesman" width="100" show-overflow-tooltip /> |
| | | <el-table-column label="项目名称" prop="projectName" width="180" show-overflow-tooltip /> |
| | |
| | | </el-row> |
| | | <el-row :gutter="30"> |
| | | <el-col :span="12"> |
| | | <el-form-item label="销售合同号:" prop="salesContractNo"> |
| | | <el-form-item label="销售单号:" prop="salesContractNo"> |
| | | <el-input v-model="form.salesContractNo" placeholder="自动生成" clearable disabled /> |
| | | </el-form-item> |
| | | </el-col> |
| | |
| | | <el-table-column label="不含税总价(元)" prop="taxExclusiveTotalPrice" :formatter="formattedNumber" /> |
| | | <el-table-column fixed="right" label="操作" min-width="60" align="center" v-if="operationType !== 'view'"> |
| | | <template #default="scope"> |
| | | <el-button link type="primary" size="small" |
| | | <el-button link type="primary" size="small" |
| | | :disabled="isProductShipped(scope.row)" |
| | | @click="openProductForm('edit', scope.row,scope.$index)">编辑</el-button> |
| | | </template> |
| | |
| | | <el-button type="primary" @click="fetchQuotationList">搜索</el-button> |
| | | <el-button @click="resetQuotationSearch">重置</el-button> |
| | | </div> |
| | | |
| | | |
| | | <el-table |
| | | :data="quotationList" |
| | | border |
| | |
| | | </template> |
| | | </el-table-column> |
| | | </el-table> |
| | | |
| | | |
| | | <pagination |
| | | v-show="quotationPage.total > 0" |
| | | :total="quotationPage.total" |
| | |
| | | :limit="quotationPage.size" |
| | | @pagination="quotationPaginationChange" |
| | | /> |
| | | |
| | | |
| | | <template #footer> |
| | | <el-button @click="quotationDialogVisible = false">关闭</el-button> |
| | | </template> |
| | |
| | | <div class="header"> |
| | | <div class="document-title">零售发货单</div> |
| | | </div> |
| | | |
| | | |
| | | <div class="info-section"> |
| | | <div class="info-row"> |
| | | <div> |
| | |
| | | <span class="value">{{ item.salesContractNo }}</span> |
| | | </div> |
| | | </div> |
| | | |
| | | |
| | | <div class="table-section"> |
| | | <table class="product-table"> |
| | | <thead> |
| | |
| | | </tfoot> |
| | | </table> |
| | | </div> |
| | | |
| | | |
| | | <div class="footer-section"> |
| | | <div class="footer-row"> |
| | | <div class="footer-item"> |
| | |
| | | <el-row :gutter="30"> |
| | | <el-col :span="24"> |
| | | <el-form-item label="发货图片:"> |
| | | <el-upload |
| | | v-model:file-list="deliveryFileList" |
| | | :action="upload.url" |
| | | multiple |
| | | ref="deliveryFileUpload" |
| | | <el-upload |
| | | v-model:file-list="deliveryFileList" |
| | | :action="upload.url" |
| | | multiple |
| | | ref="deliveryFileUpload" |
| | | auto-upload |
| | | :headers="upload.headers" |
| | | :headers="upload.headers" |
| | | :data="{ type: 9 }" |
| | | :on-success="handleDeliveryUploadSuccess" |
| | | :on-success="handleDeliveryUploadSuccess" |
| | | :on-remove="handleDeliveryRemove" |
| | | list-type="picture-card" |
| | | :limit="9" |
| | |
| | | if (children && children.length > 0) { |
| | | newItem.children = convertIdToValue(children); |
| | | } |
| | | |
| | | |
| | | return newItem; |
| | | }); |
| | | } |
| | |
| | | const applyQuotation = (row) => { |
| | | if (!row) return; |
| | | selectedQuotation.value = row; |
| | | |
| | | |
| | | // 业务员 |
| | | form.value.salesman = (row.salesperson || "").trim(); |
| | | |
| | | |
| | | // 客户名称 -> customerId |
| | | const qCustomerName = String(row.customer || "").trim(); |
| | | const customer = (customerOption.value || []).find((c) => { |
| | |
| | | // 如果找不到,保留原值(允许用户手动选择/不打断已有输入) |
| | | form.value.customerId = form.value.customerId || ""; |
| | | } |
| | | |
| | | |
| | | // 产品信息映射:报价 products -> 台账 productData |
| | | const products = Array.isArray(row.products) ? row.products : []; |
| | | productData.value = products.map((p) => { |
| | |
| | | invoiceType: "增普票", |
| | | }; |
| | | }); |
| | | |
| | | |
| | | quotationDialogVisible.value = false; |
| | | }; |
| | | function changs(val) { |
| | |
| | | proxy.$modal.msgWarning("已发货或审核通过的产品不能编辑"); |
| | | return; |
| | | } |
| | | |
| | | |
| | | productOperationType.value = type; |
| | | productForm.value = {}; |
| | | proxy.resetForm("productFormRef"); |
| | |
| | | proxy.$modal.msgWarning("请选择数据"); |
| | | return; |
| | | } |
| | | |
| | | |
| | | // 检查是否有已发货或审核通过的产品 |
| | | const shippedProducts = productSelectedRows.value.filter(row => isProductShipped(row)); |
| | | if (shippedProducts.length > 0) { |
| | | proxy.$modal.msgWarning("已发货或审核通过的产品不能删除"); |
| | | return; |
| | | } |
| | | |
| | | |
| | | if (operationType.value === "add") { |
| | | productSelectedRows.value.forEach((selectedRow) => { |
| | | const index = productData.value.findIndex( |
| | |
| | | proxy.$modal.msgWarning("请选择要打印的数据"); |
| | | return; |
| | | } |
| | | |
| | | |
| | | // 显示加载状态 |
| | | proxy.$modal.loading("正在获取产品数据,请稍候..."); |
| | | |
| | | |
| | | try { |
| | | // 为每个选中的销售台账记录查询对应的产品数据 |
| | | const printDataWithProducts = []; |
| | | |
| | | |
| | | for (const row of selectedRows.value) { |
| | | try { |
| | | // 调用productList接口查询产品数据 |
| | | const productRes = await productList({ salesLedgerId: row.id, type: 1 }); |
| | | |
| | | |
| | | // 将产品数据整合到销售台账记录中 |
| | | const rowWithProducts = { |
| | | ...row, |
| | | products: productRes.data || [] |
| | | }; |
| | | |
| | | |
| | | printDataWithProducts.push(rowWithProducts); |
| | | } catch (error) { |
| | | console.error(`获取销售台账 ${row.id} 的产品数据失败:`, error); |
| | |
| | | }); |
| | | } |
| | | } |
| | | |
| | | |
| | | printData.value = printDataWithProducts; |
| | | console.log('打印数据(包含产品):', printData.value); |
| | | printPreviewVisible.value = true; |
| | | |
| | | |
| | | } catch (error) { |
| | | console.error('获取产品数据失败:', error); |
| | | proxy.$modal.msgError("获取产品数据失败,请重试"); |
| | |
| | | const executePrint = () => { |
| | | console.log('开始执行打印,数据条数:', printData.value.length); |
| | | console.log('打印数据:', printData.value); |
| | | |
| | | |
| | | // 创建一个新的打印窗口 |
| | | const printWindow = window.open('', '_blank', 'width=800,height=600'); |
| | | |
| | | |
| | | // 构建打印内容 |
| | | let printContent = ` |
| | | <!DOCTYPE html> |
| | |
| | | </head> |
| | | <body> |
| | | `; |
| | | |
| | | |
| | | // 为每条数据生成打印页面 |
| | | printData.value.forEach((item, index) => { |
| | | printContent += ` |
| | |
| | | <div class="header"> |
| | | <div class="document-title">零售发货单</div> |
| | | </div> |
| | | |
| | | |
| | | <div class="info-section"> |
| | | <div class="info-row"> |
| | | <div> |
| | |
| | | </div> |
| | | `; |
| | | }); |
| | | |
| | | |
| | | printContent += ` |
| | | </body> |
| | | </html> |
| | | `; |
| | | |
| | | |
| | | // 写入内容到新窗口 |
| | | printWindow.document.write(printContent); |
| | | printWindow.document.close(); |
| | | |
| | | |
| | | // 等待内容加载完成后打印 |
| | | printWindow.onload = () => { |
| | | setTimeout(() => { |
| | |
| | | // 根据含税总价计算含税单价和数量 |
| | | const calculateFromTotalPrice = () => { |
| | | if (isCalculating.value) return; |
| | | |
| | | |
| | | const totalPrice = parseFloat(productForm.value.taxInclusiveTotalPrice); |
| | | const quantity = parseFloat(productForm.value.quantity); |
| | | |
| | | |
| | | if (!totalPrice || !quantity || quantity <= 0) { |
| | | return; |
| | | } |
| | | |
| | | |
| | | isCalculating.value = true; |
| | | |
| | | |
| | | // 计算含税单价 = 含税总价 / 数量 |
| | | productForm.value.taxInclusiveUnitPrice = (totalPrice / quantity).toFixed(2); |
| | | |
| | | |
| | | // 如果有税率,计算不含税总价 |
| | | if (productForm.value.taxRate) { |
| | | productForm.value.taxExclusiveTotalPrice = |
| | |
| | | productForm.value.taxRate |
| | | ); |
| | | } |
| | | |
| | | |
| | | isCalculating.value = false; |
| | | }; |
| | | |
| | |
| | | return; |
| | | } |
| | | if (isCalculating.value) return; |
| | | |
| | | |
| | | const exclusiveTotalPrice = parseFloat(productForm.value.taxExclusiveTotalPrice); |
| | | const quantity = parseFloat(productForm.value.quantity); |
| | | const taxRate = parseFloat(productForm.value.taxRate); |
| | | |
| | | |
| | | if (!exclusiveTotalPrice || !quantity || quantity <= 0 || !taxRate) { |
| | | return; |
| | | } |
| | | |
| | | |
| | | isCalculating.value = true; |
| | | |
| | | |
| | | // 先计算含税总价 = 不含税总价 / (1 - 税率/100) |
| | | const taxRateDecimal = taxRate / 100; |
| | | const inclusiveTotalPrice = exclusiveTotalPrice / (1 - taxRateDecimal); |
| | | productForm.value.taxInclusiveTotalPrice = inclusiveTotalPrice.toFixed(2); |
| | | |
| | | |
| | | // 计算含税单价 = 含税总价 / 数量 |
| | | productForm.value.taxInclusiveUnitPrice = (inclusiveTotalPrice / quantity).toFixed(2); |
| | | |
| | | |
| | | isCalculating.value = false; |
| | | }; |
| | | |
| | |
| | | return; |
| | | } |
| | | if (isCalculating.value) return; |
| | | |
| | | |
| | | const quantity = parseFloat(productForm.value.quantity); |
| | | const unitPrice = parseFloat(productForm.value.taxInclusiveUnitPrice); |
| | | |
| | | |
| | | if (!quantity || quantity <= 0 || !unitPrice) { |
| | | return; |
| | | } |
| | | |
| | | |
| | | isCalculating.value = true; |
| | | |
| | | |
| | | // 计算含税总价 |
| | | productForm.value.taxInclusiveTotalPrice = (unitPrice * quantity).toFixed(2); |
| | | |
| | | |
| | | // 如果有税率,计算不含税总价 |
| | | if (productForm.value.taxRate) { |
| | | productForm.value.taxExclusiveTotalPrice = |
| | |
| | | productForm.value.taxRate |
| | | ); |
| | | } |
| | | |
| | | |
| | | isCalculating.value = false; |
| | | }; |
| | | |
| | |
| | | return; |
| | | } |
| | | if (isCalculating.value) return; |
| | | |
| | | |
| | | const quantity = parseFloat(productForm.value.quantity); |
| | | const unitPrice = parseFloat(productForm.value.taxInclusiveUnitPrice); |
| | | |
| | | |
| | | if (!quantity || quantity <= 0 || !unitPrice) { |
| | | return; |
| | | } |
| | | |
| | | |
| | | isCalculating.value = true; |
| | | |
| | | |
| | | // 计算含税总价 |
| | | productForm.value.taxInclusiveTotalPrice = (unitPrice * quantity).toFixed(2); |
| | | |
| | | |
| | | // 如果有税率,计算不含税总价 |
| | | if (productForm.value.taxRate) { |
| | | productForm.value.taxExclusiveTotalPrice = |
| | |
| | | productForm.value.taxRate |
| | | ); |
| | | } |
| | | |
| | | |
| | | isCalculating.value = false; |
| | | }; |
| | | |
| | |
| | | return; |
| | | } |
| | | if (isCalculating.value) return; |
| | | |
| | | |
| | | const inclusiveTotalPrice = parseFloat(productForm.value.taxInclusiveTotalPrice); |
| | | const taxRate = parseFloat(productForm.value.taxRate); |
| | | |
| | | |
| | | if (!inclusiveTotalPrice || !taxRate) { |
| | | return; |
| | | } |
| | | |
| | | |
| | | isCalculating.value = true; |
| | | |
| | | |
| | | // 计算不含税总价 |
| | | productForm.value.taxExclusiveTotalPrice = |
| | | proxy.calculateTaxExclusiveTotalPrice( |
| | | inclusiveTotalPrice, |
| | | taxRate |
| | | ); |
| | | |
| | | |
| | | isCalculating.value = false; |
| | | }; |
| | | /** |
| | |
| | | if (row.shippingDate || row.shippingCarNumber) { |
| | | return '已发货'; |
| | | } |
| | | |
| | | |
| | | // 获取发货状态字段 |
| | | const status = row.shippingStatus; |
| | | |
| | | |
| | | // 如果状态为空或未定义,默认为"待发货" |
| | | if (status === null || status === undefined || status === '') { |
| | | return '待发货'; |
| | | } |
| | | |
| | | |
| | | // 状态是字符串 |
| | | const statusStr = String(status).trim(); |
| | | const statusTextMap = { |
| | |
| | | if (row.shippingDate || row.shippingCarNumber) { |
| | | return 'success'; |
| | | } |
| | | |
| | | |
| | | // 获取发货状态字段 |
| | | const status = row.shippingStatus; |
| | | |
| | | |
| | | // 如果状态为空或未定义,默认为灰色(待发货) |
| | | if (status === null || status === undefined || status === '') { |
| | | return 'info'; |
| | | } |
| | | |
| | | |
| | | // 状态是字符串 |
| | | const statusStr = String(status).trim(); |
| | | const typeTextMap = { |
| | |
| | | if (row.approveStatus !== 1) { |
| | | return false; |
| | | } |
| | | |
| | | |
| | | // 获取发货状态 |
| | | const shippingStatus = row.shippingStatus; |
| | | |
| | | |
| | | // 如果已发货(有发货日期或车牌号),不能再次发货 |
| | | if (row.shippingDate || row.shippingCarNumber) { |
| | | return false; |
| | | } |
| | | |
| | | |
| | | // 发货状态必须是"待发货"或"审核拒绝" |
| | | const statusStr = shippingStatus ? String(shippingStatus).trim() : ''; |
| | | return statusStr === '待发货' || statusStr === '审核拒绝'; |
| | |
| | | proxy.$modal.msgWarning("只有在产品状态是充足,发货状态是待发货或审核拒绝的时候才可以发货"); |
| | | return; |
| | | } |
| | | |
| | | |
| | | currentDeliveryRow.value = row; |
| | | deliveryForm.value = { |
| | | type: "货车", |
| | |
| | | // 保存当前展开的行ID,以便发货后重新加载子表格数据 |
| | | const currentExpandedKeys = [...expandedRowKeys.value]; |
| | | const salesLedgerId = currentDeliveryRow.value.salesLedgerId; |
| | | |
| | | |
| | | // 获取上传图片的临时ID |
| | | let tempFileIds = []; |
| | | if (deliveryFileList.value !== null && deliveryFileList.value.length > 0) { |
| | | tempFileIds = deliveryFileList.value.map((item) => item.tempId); |
| | | } |
| | | |
| | | |
| | | addShippingInfo({ |
| | | salesLedgerId: salesLedgerId, |
| | | salesLedgerProductId: currentDeliveryRow.value.id, |
| | |
| | | padding: 15px; |
| | | border-bottom: 1px solid #e4e7ed; |
| | | text-align: center; |
| | | |
| | | |
| | | .el-button { |
| | | margin: 0 10px; |
| | | } |
| | | } |
| | | |
| | | |
| | | .print-preview-content { |
| | | padding: 20px; |
| | | background-color: #f5f5f5; |
| | |
| | | .header { |
| | | text-align: center; |
| | | margin-bottom: 8px; |
| | | |
| | | |
| | | .company-name { |
| | | font-size: 18px; |
| | | font-weight: bold; |
| | | margin-bottom: 4px; |
| | | } |
| | | |
| | | |
| | | .document-title { |
| | | font-size: 16px; |
| | | font-weight: bold; |
| | |
| | | display: flex; |
| | | justify-content: space-between; |
| | | align-items: center; |
| | | |
| | | |
| | | .info-row { |
| | | line-height: 20px; |
| | | |
| | | |
| | | .label { |
| | | font-weight: bold; |
| | | width: 60px; |
| | | font-size: 14px; |
| | | } |
| | | |
| | | |
| | | .value { |
| | | margin-right: 20px; |
| | | min-width: 80px; |
| | |
| | | .table-section { |
| | | margin-bottom: 4px; |
| | | flex: 1; |
| | | |
| | | |
| | | .product-table { |
| | | width: 100%; |
| | | border-collapse: collapse; |
| | | border: 1px solid #000; |
| | | |
| | | |
| | | th, td { |
| | | border: 1px solid #000; |
| | | padding: 6px; |
| | |
| | | font-size: 14px; |
| | | line-height: 1.4; |
| | | } |
| | | |
| | | |
| | | th { |
| | | font-weight: bold; |
| | | } |
| | | |
| | | |
| | | .total-label { |
| | | text-align: right; |
| | | font-weight: bold; |
| | | } |
| | | |
| | | |
| | | .total-value { |
| | | font-weight: bold; |
| | | } |
| | |
| | | margin-bottom: 3px; |
| | | line-height: 20px; |
| | | justify-content: space-between; |
| | | |
| | | |
| | | .footer-item { |
| | | display: flex; |
| | | margin-right: 20px; |
| | | |
| | | |
| | | .label { |
| | | font-weight: bold; |
| | | width: 80px; |
| | | font-size: 14px; |
| | | } |
| | | |
| | | |
| | | .value { |
| | | min-width: 80px; |
| | | font-size: 14px; |
| | | } |
| | | |
| | | |
| | | &.address-item { |
| | | .address-value { |
| | | min-width: 200px; |
| | |
| | | .app-container { |
| | | display: none; |
| | | } |
| | | |
| | | |
| | | .print-page { |
| | | box-shadow: none; |
| | | margin: 0; |