| | |
| | | prefix-icon="Search" |
| | | @change="handleQuery" /> |
| | | </el-form-item> |
| | | <el-form-item label="供应商类型:"> |
| | | <el-select v-model="searchForm.supplierType" |
| | | placeholder="请选择" |
| | | style="width: 220px" |
| | | clearable |
| | | @change="handleQuery"> |
| | | <el-option label="对公" |
| | | value="1" /> |
| | | <el-option label="对私" |
| | | value="2" /> |
| | | </el-select> |
| | | </el-form-item> |
| | | <el-form-item label="录入日期:"> |
| | | <el-date-picker v-model="searchForm.entryDate" |
| | | value-format="YYYY-MM-DD" |
| | |
| | | <div style="display: flex;justify-content: flex-end;margin-bottom: 20px;"> |
| | | <el-button type="primary" |
| | | @click="openForm('add')">新增台账</el-button> |
| | | <el-button type="primary" plain @click="handleImport">导入</el-button> |
| | | <el-button type="primary" |
| | | plain |
| | | @click="handleImport">导入</el-button> |
| | | <el-button @click="handleOut">导出</el-button> |
| | | <el-button type="danger" |
| | | plain |
| | |
| | | prop="availableQuality" /> |
| | | <el-table-column label="退货数量" |
| | | prop="returnQuality" /> |
| | | |
| | | <el-table-column label="税率(%)" |
| | | prop="taxRate" /> |
| | | prop="taxRate" |
| | | v-if="props.row.supplierType === 1" /> |
| | | <el-table-column label="含税单价(元)" |
| | | prop="taxInclusiveUnitPrice" |
| | | :formatter="formattedNumber" /> |
| | | :formatter="formattedNumber" |
| | | v-if="props.row.supplierType === 1" /> |
| | | <el-table-column label="含税总价(元)" |
| | | prop="taxInclusiveTotalPrice" |
| | | :formatter="formattedNumber" /> |
| | | :formatter="formattedNumber" |
| | | v-if="props.row.supplierType === 1" /> |
| | | <el-table-column label="不含税总价(元)" |
| | | prop="taxExclusiveTotalPrice" |
| | | :formatter="formattedNumber" /> |
| | | :formatter="formattedNumber" |
| | | v-if="props.row.supplierType === 1" /> |
| | | <el-table-column label="单价(对私)" |
| | | prop="unitPrice" |
| | | :formatter="formattedNumber" |
| | | v-if="props.row.supplierType === 2" /> |
| | | <el-table-column label="总价(对私)" |
| | | prop="totalPrice" |
| | | :formatter="formattedNumber" |
| | | v-if="props.row.supplierType === 2" /> |
| | | </el-table> |
| | | </template> |
| | | </el-table-column> |
| | |
| | | show-overflow-tooltip /> |
| | | <el-table-column label="销售合同号" |
| | | prop="salesContractNo" |
| | | width="160" |
| | | width="160" |
| | | show-overflow-tooltip /> |
| | | <el-table-column label="供应商名称" |
| | | prop="supplierName" |
| | | width="160" |
| | | width="160" |
| | | show-overflow-tooltip /> |
| | | <el-table-column label="供应商类型" |
| | | prop="supplierType" |
| | | width="100" |
| | | show-overflow-tooltip> |
| | | <template #default="scope"> |
| | | {{ scope.row.supplierType === 1 ? '对公' : '对私' }} |
| | | </template> |
| | | </el-table-column> |
| | | <el-table-column label="项目名称" |
| | | prop="projectName" |
| | | width="320" |
| | |
| | | width="100" |
| | | show-overflow-tooltip> |
| | | <template #default="scope"> |
| | | <el-tag |
| | | :type="getApprovalStatusType(scope.row.approvalStatus)" |
| | | size="small"> |
| | | <el-tag :type="getApprovalStatusType(scope.row.approvalStatus)" |
| | | size="small"> |
| | | {{ approvalStatusText[scope.row.approvalStatus] || '未知状态' }} |
| | | </el-tag> |
| | | </template> |
| | |
| | | @pagination="paginationChange" /> |
| | | </div> |
| | | <FormDialog v-model="dialogFormVisible" |
| | | :title="operationType === 'add' ? '新增采购台账页面' : '编辑采购台账页面'" |
| | | :width="'70%'" |
| | | :operation-type="operationType" |
| | | @close="closeDia" |
| | | @confirm="submitForm" |
| | | @cancel="closeDia"> |
| | | :title="operationType === 'add' ? '新增采购台账页面' : '编辑采购台账页面'" |
| | | :width="'70%'" |
| | | :operation-type="operationType" |
| | | @close="closeDia" |
| | | @confirm="submitForm" |
| | | @cancel="closeDia"> |
| | | <el-form :model="form" |
| | | label-width="140px" |
| | | label-position="top" |
| | |
| | | <el-select v-model="form.supplierId" |
| | | placeholder="请选择" |
| | | filterable |
| | | clearable> |
| | | clearable |
| | | @change="handleSupplierChange"> |
| | | <el-option v-for="item in supplierList" |
| | | :key="item.id" |
| | | :label="item.supplierName" |
| | | :value="item.id" >{{item.supplierName + '---' + item.supplierType}}</el-option> |
| | | :value="item.id">{{item.supplierName + '---' + (item.supplierType === 1 ? item.taxpayerIdentificationNum || '无' : '对私')}}</el-option> |
| | | </el-select> |
| | | </el-form-item> |
| | | </el-col> |
| | |
| | | <template #label> |
| | | <div style="display: flex; align-items: center; justify-content: space-between; width: 100%;"> |
| | | <span>审批人选择:</span> |
| | | <el-button type="primary" size="small" @click="addApproverNode" icon="Plus">新增节点</el-button> |
| | | <el-button type="primary" |
| | | size="small" |
| | | @click="addApproverNode" |
| | | icon="Plus">新增节点</el-button> |
| | | </div> |
| | | </template> |
| | | <div class="approver-nodes-container"> |
| | | <div |
| | | v-for="(node, index) in approverNodes" |
| | | :key="node.id" |
| | | class="approver-node-item" |
| | | > |
| | | <div v-for="(node, index) in approverNodes" |
| | | :key="node.id" |
| | | class="approver-node-item"> |
| | | <div class="approver-node-header"> |
| | | <span class="approver-node-label">审批节点 {{ index + 1 }}</span> |
| | | <el-button |
| | | v-if="approverNodes.length > 1" |
| | | type="danger" |
| | | size="small" |
| | | text |
| | | @click="removeApproverNode(index)" |
| | | icon="Delete" |
| | | >删除</el-button> |
| | | <el-button v-if="approverNodes.length > 1" |
| | | type="danger" |
| | | size="small" |
| | | text |
| | | @click="removeApproverNode(index)" |
| | | icon="Delete">删除</el-button> |
| | | </div> |
| | | <el-select |
| | | v-model="node.userId" |
| | | placeholder="请选择审批人" |
| | | filterable |
| | | style="width: 100%;" |
| | | > |
| | | <el-option |
| | | v-for="user in userList" |
| | | :key="user.userId" |
| | | :label="user.nickName" |
| | | :value="user.userId" |
| | | /> |
| | | <el-select v-model="node.userId" |
| | | placeholder="请选择审批人" |
| | | filterable |
| | | style="width: 100%;"> |
| | | <el-option v-for="user in userList" |
| | | :key="user.userId" |
| | | :label="user.nickName" |
| | | :value="user.userId" /> |
| | | </el-select> |
| | | </div> |
| | | </div> |
| | |
| | | <el-form-item label="产品信息:" |
| | | prop="entryDate"> |
| | | <el-button type="primary" |
| | | v-if="currentSupplierType" |
| | | @click="openProductForm('add')">添加</el-button> |
| | | <el-button plain |
| | | type="danger" |
| | |
| | | :value="item.templateName"> |
| | | <div style="display: flex; justify-content: space-between; align-items: center;"> |
| | | <span>{{ item.templateName }}</span> |
| | | <el-icon |
| | | v-if="item.id" |
| | | class="delete-icon" |
| | | @click.stop="handleDeleteTemplate(item)" |
| | | style="cursor: pointer; color: #f56c6c; font-size: 14px; margin-left: 8px;"> |
| | | <el-icon v-if="item.id" |
| | | class="delete-icon" |
| | | @click.stop="handleDeleteTemplate(item)" |
| | | style="cursor: pointer; color: #f56c6c; font-size: 14px; margin-left: 8px;"> |
| | | <Delete /> |
| | | </el-icon> |
| | | </div> |
| | |
| | | show-overflow-tooltip /> |
| | | <el-table-column label="税率(%)" |
| | | prop="taxRate" |
| | | width="80" /> |
| | | width="80" |
| | | v-if="currentSupplierType === 1" /> |
| | | <el-table-column label="含税单价(元)" |
| | | prop="taxInclusiveUnitPrice" |
| | | :formatter="formattedNumber" |
| | | width="150" /> |
| | | width="150" |
| | | v-if="currentSupplierType === 1" /> |
| | | <el-table-column label="含税总价(元)" |
| | | prop="taxInclusiveTotalPrice" |
| | | :formatter="formattedNumber" |
| | | width="150" /> |
| | | width="150" |
| | | v-if="currentSupplierType === 1" /> |
| | | <el-table-column label="不含税总价(元)" |
| | | prop="taxExclusiveTotalPrice" |
| | | :formatter="formattedNumber" |
| | | width="150" /> |
| | | width="150" |
| | | v-if="currentSupplierType === 1" /> |
| | | <el-table-column label="单价(对私)" |
| | | prop="unitPrice" |
| | | :formatter="formattedNumber" |
| | | width="150" |
| | | v-if="currentSupplierType === 2" /> |
| | | <el-table-column label="总价(对私)" |
| | | prop="totalPrice" |
| | | :formatter="formattedNumber" |
| | | width="150" |
| | | v-if="currentSupplierType === 2" /> |
| | | <el-table-column label="是否质检" |
| | | prop="isChecked" |
| | | width="150"> |
| | |
| | | </el-form> |
| | | </FormDialog> |
| | | <!-- 导入弹窗 --> |
| | | <FormDialog |
| | | v-model="importUpload.open" |
| | | :title="importUpload.title" |
| | | :width="'600px'" |
| | | @close="importUpload.open = false" |
| | | @confirm="submitImportFile" |
| | | @cancel="importUpload.open = false" |
| | | > |
| | | <el-upload |
| | | ref="importUploadRef" |
| | | :limit="1" |
| | | accept=".xlsx,.xls" |
| | | :action="importUpload.url" |
| | | :headers="importUpload.headers" |
| | | :before-upload="importUpload.beforeUpload" |
| | | :on-success="importUpload.onSuccess" |
| | | :on-error="importUpload.onError" |
| | | :on-progress="importUpload.onProgress" |
| | | :on-change="importUpload.onChange" |
| | | :auto-upload="false" |
| | | drag |
| | | > |
| | | <FormDialog v-model="importUpload.open" |
| | | :title="importUpload.title" |
| | | :width="'600px'" |
| | | @close="importUpload.open = false" |
| | | @confirm="submitImportFile" |
| | | @cancel="importUpload.open = false"> |
| | | <el-upload ref="importUploadRef" |
| | | :limit="1" |
| | | accept=".xlsx,.xls" |
| | | :action="importUpload.url" |
| | | :headers="importUpload.headers" |
| | | :before-upload="importUpload.beforeUpload" |
| | | :on-success="importUpload.onSuccess" |
| | | :on-error="importUpload.onError" |
| | | :on-progress="importUpload.onProgress" |
| | | :on-change="importUpload.onChange" |
| | | :auto-upload="false" |
| | | drag> |
| | | <i class="el-icon-upload"></i> |
| | | <div class="el-upload__text"> |
| | | 将文件拖到此处,或<em>点击上传</em> |
| | |
| | | <template #tip> |
| | | <div class="el-upload__tip"> |
| | | 仅支持 xls/xlsx,大小不超过 10MB。 |
| | | <el-button link type="primary" @click="downloadTemplate">下载导入模板</el-button> |
| | | <el-button link |
| | | type="primary" |
| | | @click="downloadTemplate">下载导入模板</el-button> |
| | | </div> |
| | | </template> |
| | | </el-upload> |
| | | </FormDialog> |
| | | <FormDialog v-model="productFormVisible" |
| | | :title="productOperationType === 'add' ? '新增产品' : '编辑产品'" |
| | | :width="'40%'" |
| | | :operation-type="productOperationType" |
| | | @close="closeProductDia" |
| | | @confirm="submitProduct" |
| | | @cancel="closeProductDia"> |
| | | :title="productOperationType === 'add' ? '新增产品' : '编辑产品'" |
| | | :width="'40%'" |
| | | :operation-type="productOperationType" |
| | | @close="closeProductDia" |
| | | @confirm="submitProduct" |
| | | @cancel="closeProductDia"> |
| | | <el-form :model="productForm" |
| | | label-width="140px" |
| | | label-position="top" |
| | | :rules="productRules" |
| | | :rules="getProductRules()" |
| | | ref="productFormRef"> |
| | | <el-row :gutter="30"> |
| | | <el-col :span="24"> |
| | |
| | | </el-col> |
| | | <el-col :span="12"> |
| | | <el-form-item label="税率(%):" |
| | | prop="taxRate"> |
| | | prop="taxRate" |
| | | v-if="currentSupplierType === 1"> |
| | | <el-select v-model="productForm.taxRate" |
| | | placeholder="请选择" |
| | | clearable |
| | |
| | | </el-row> |
| | | <el-row :gutter="30"> |
| | | <el-col :span="12"> |
| | | <el-form-item label="含税单价(元):" |
| | | prop="taxInclusiveUnitPrice"> |
| | | <el-input-number v-model="productForm.taxInclusiveUnitPrice" |
| | | :precision="2" |
| | | :step="0.1" |
| | | :min="0" |
| | | clearable |
| | | style="width: 100%" |
| | | @change="mathNum" /> |
| | | </el-form-item> |
| | | </el-col> |
| | | <el-col :span="12"> |
| | | <el-form-item label="数量:" |
| | | prop="quantity"> |
| | | <el-input-number :step="0.1" |
| | |
| | | style="width: 100%" |
| | | v-model="productForm.quantity" |
| | | placeholder="请输入" |
| | | @change="currentSupplierType === 1 ? mathNum() : mathNumPrivate()" /> |
| | | </el-form-item> |
| | | </el-col> |
| | | <el-col :span="12"> |
| | | <el-form-item label="含税单价(元):" |
| | | prop="taxInclusiveUnitPrice" |
| | | v-if="currentSupplierType === 1"> |
| | | <el-input-number v-model="productForm.taxInclusiveUnitPrice" |
| | | :precision="2" |
| | | :step="0.1" |
| | | :min="0" |
| | | clearable |
| | | style="width: 100%" |
| | | @change="mathNum" /> |
| | | </el-form-item> |
| | | <el-form-item label="单价(对私):" |
| | | prop="unitPrice" |
| | | v-else> |
| | | <el-input-number v-model="productForm.unitPrice" |
| | | :precision="2" |
| | | :step="0.1" |
| | | :min="0" |
| | | clearable |
| | | style="width: 100%" |
| | | @change="mathNumPrivate" /> |
| | | </el-form-item> |
| | | </el-col> |
| | | </el-row> |
| | | <el-row :gutter="30"> |
| | | <el-col :span="12"> |
| | | <el-form-item label="含税总价(元):" |
| | | prop="taxInclusiveTotalPrice"> |
| | | prop="taxInclusiveTotalPrice" |
| | | v-if="currentSupplierType === 1"> |
| | | <el-input-number v-model="productForm.taxInclusiveTotalPrice" |
| | | :precision="2" |
| | | :step="0.1" |
| | |
| | | style="width: 100%" |
| | | @change="reverseMathNum('taxInclusiveTotalPrice')" /> |
| | | </el-form-item> |
| | | <el-form-item label="总价(对私):" |
| | | prop="totalPrice" |
| | | v-else> |
| | | <el-input-number v-model="productForm.totalPrice" |
| | | :precision="2" |
| | | :step="0.1" |
| | | :min="0" |
| | | clearable |
| | | style="width: 100%" |
| | | @change="reverseMathNumPrivate('totalPrice')" /> |
| | | </el-form-item> |
| | | </el-col> |
| | | <el-col v-if="currentSupplierType === 2" |
| | | :span="12"> |
| | | <el-form-item label="库存预警数量:" |
| | | prop="warnNum"> |
| | | <el-input-number v-model="productForm.warnNum" |
| | | :precision="2" |
| | | :step="0.1" |
| | | :min="0" |
| | | clearable |
| | | style="width: 100%" /> |
| | | </el-form-item> |
| | | </el-col> |
| | | <el-col :span="12"> |
| | | <el-form-item label="不含税总价(元):" |
| | | prop="taxExclusiveTotalPrice"> |
| | | prop="taxExclusiveTotalPrice" |
| | | v-if="currentSupplierType === 1"> |
| | | <el-input-number v-model="productForm.taxExclusiveTotalPrice" |
| | | :precision="2" |
| | | :step="0.1" |
| | |
| | | <el-row :gutter="30"> |
| | | <el-col :span="12"> |
| | | <el-form-item label="发票类型:" |
| | | prop="invoiceType"> |
| | | prop="invoiceType" |
| | | v-if="currentSupplierType === 1"> |
| | | <el-select v-model="productForm.invoiceType" |
| | | placeholder="请选择" |
| | | clearable> |
| | |
| | | </el-select> |
| | | </el-form-item> |
| | | </el-col> |
| | | <el-col :span="12"> |
| | | <el-col v-if="currentSupplierType === 1" |
| | | :span="12"> |
| | | <el-form-item label="库存预警数量:" |
| | | prop="warnNum"> |
| | | <el-input-number v-model="productForm.warnNum" |
| | |
| | | </el-row> |
| | | </el-form> |
| | | </FormDialog> |
| | | <FileListDialog |
| | | ref="fileListRef" |
| | | v-model="fileListDialogVisible" |
| | | title="附件列表" |
| | | /> |
| | | <FileListDialog ref="fileListRef" |
| | | v-model="fileListDialogVisible" |
| | | title="附件列表" /> |
| | | </div> |
| | | </template> |
| | | |
| | |
| | | import { Search, Delete } from "@element-plus/icons-vue"; |
| | | import { ElMessageBox, ElMessage } from "element-plus"; |
| | | import { userListNoPage } from "@/api/system/user.js"; |
| | | import FormDialog from '@/components/Dialog/FormDialog.vue'; |
| | | import FileListDialog from '@/components/Dialog/FileListDialog.vue'; |
| | | import FormDialog from "@/components/Dialog/FormDialog.vue"; |
| | | import FileListDialog from "@/components/Dialog/FileListDialog.vue"; |
| | | import { |
| | | getSalesLedgerWithProducts, |
| | | addOrUpdateSalesLedgerProduct, |
| | |
| | | const salesContractList = ref([]); |
| | | const supplierList = ref([]); |
| | | const tableLoading = ref(false); |
| | | const currentSupplierType = ref(null); // 跟踪当前选择的供应商类型 |
| | | const page = reactive({ |
| | | current: 1, |
| | | size: 100, |
| | |
| | | const addApproverNode = () => { |
| | | approverNodes.value.push({ id: nextApproverId++, userId: null }); |
| | | }; |
| | | const removeApproverNode = (index) => { |
| | | const removeApproverNode = index => { |
| | | approverNodes.value.splice(index, 1); |
| | | }; |
| | | |
| | | // 订单审批状态显示文本 |
| | | // 处理供应商选择变化 |
| | | const handleSupplierChange = async supplierId => { |
| | | const selectedSupplier = supplierList.value.find( |
| | | item => item.id === supplierId |
| | | ); |
| | | if (selectedSupplier) { |
| | | // 只有当当前供应商类型不为 null 且发生变化时,才清空产品表 |
| | | // 这样在编辑时加载数据后调用该函数不会清空产品数据 |
| | | if ( |
| | | currentSupplierType.value !== null && |
| | | currentSupplierType.value !== selectedSupplier.supplierType |
| | | ) { |
| | | productData.value = []; |
| | | } |
| | | currentSupplierType.value = selectedSupplier.supplierType; |
| | | } else { |
| | | currentSupplierType.value = null; |
| | | productData.value = []; |
| | | } |
| | | await getTemplateList(); |
| | | }; |
| | | const approvalStatusText = { |
| | | 1: "待审核", |
| | | 2: "审批中", |
| | |
| | | }; |
| | | |
| | | // 获取审批状态标签类型 |
| | | const getApprovalStatusType = (status) => { |
| | | const getApprovalStatusType = status => { |
| | | const typeMap = { |
| | | 1: "info", // 待审核 - 灰色 |
| | | 2: "warning", // 审批中 - 橙色 |
| | | 3: "success", // 审批通过 - 绿色 |
| | | 4: "danger", // 审批失败 - 红色 |
| | | 1: "info", // 待审核 - 灰色 |
| | | 2: "warning", // 审批中 - 橙色 |
| | | 3: "success", // 审批通过 - 绿色 |
| | | 4: "danger", // 审批失败 - 红色 |
| | | }; |
| | | return typeMap[status] || ""; |
| | | }; |
| | |
| | | form.value.paymentMethod = matchedTemplate.paymentMethod; |
| | | } |
| | | // 模板数据中的产品字段是 productList,需要转换为 productData |
| | | productData.value = matchedTemplate.productList || matchedTemplate.productData || []; |
| | | productData.value = |
| | | matchedTemplate.productList || matchedTemplate.productData || []; |
| | | } else { |
| | | // 未匹配到已有模板,视为新模板 |
| | | currentTemplateId.value = null; |
| | |
| | | entryDate: null, // 录入日期 |
| | | entryDateStart: undefined, |
| | | entryDateEnd: undefined, |
| | | supplierType: "", // 供应商类型 |
| | | }, |
| | | form: { |
| | | purchaseContractNumber: "", |
| | |
| | | }, |
| | | }); |
| | | const { productForm, productRules } = toRefs(productFormData); |
| | | const getProductRules = () => { |
| | | const baseRules = { |
| | | productId: [{ required: true, message: "请选择", trigger: "change" }], |
| | | productModelId: [{ required: true, message: "请选择", trigger: "change" }], |
| | | unit: [{ required: true, message: "请输入", trigger: "blur" }], |
| | | quantity: [{ required: true, message: "请输入", trigger: "blur" }], |
| | | warnNum: [{ required: true, message: "请选择", trigger: "change" }], |
| | | isChecked: [{ required: true, message: "请选择", trigger: "change" }], |
| | | }; |
| | | |
| | | if (currentSupplierType.value === 1) { |
| | | // 对公供应商需要验证的字段 |
| | | return { |
| | | ...baseRules, |
| | | taxInclusiveUnitPrice: [ |
| | | { required: true, message: "请输入", trigger: "blur" }, |
| | | ], |
| | | taxRate: [{ required: true, message: "请选择", trigger: "change" }], |
| | | taxInclusiveTotalPrice: [ |
| | | { required: true, message: "请输入", trigger: "blur" }, |
| | | ], |
| | | taxExclusiveTotalPrice: [ |
| | | { required: true, message: "请输入", trigger: "blur" }, |
| | | ], |
| | | invoiceType: [{ required: true, message: "请选择", trigger: "change" }], |
| | | }; |
| | | } else if (currentSupplierType.value === 2) { |
| | | // 对私供应商需要验证的字段 |
| | | return { |
| | | ...baseRules, |
| | | unitPrice: [{ required: true, message: "请输入", trigger: "blur" }], |
| | | totalPrice: [{ required: true, message: "请输入", trigger: "blur" }], |
| | | }; |
| | | } else { |
| | | return baseRules; |
| | | } |
| | | }; |
| | | const upload = reactive({ |
| | | // 上传的地址 |
| | | url: import.meta.env.VITE_APP_BASE_API + "/file/upload", |
| | |
| | | url: import.meta.env.VITE_APP_BASE_API + "/purchase/ledger/import", |
| | | headers: { Authorization: "Bearer " + getToken() }, |
| | | isUploading: false, |
| | | beforeUpload: (file) => { |
| | | beforeUpload: file => { |
| | | const isExcel = file.name.endsWith(".xlsx") || file.name.endsWith(".xls"); |
| | | const isLt10M = file.size / 1024 / 1024 < 10; |
| | | if (!isExcel) { |
| | |
| | | |
| | | // 下载导入模板(如后端路径不同,可在此处调整) |
| | | const downloadTemplate = () => { |
| | | proxy.download("/purchase/ledger/exportTemplate", {}, "采购台账导入模板.xlsx"); |
| | | proxy.download( |
| | | "/purchase/ledger/exportTemplate", |
| | | {}, |
| | | "采购台账导入模板.xlsx" |
| | | ); |
| | | }; |
| | | |
| | | const submitImportFile = () => { |
| | |
| | | // 检查是否有产品数据 |
| | | if (!productData.value || productData.value.length === 0) { |
| | | ElMessage({ |
| | | message: '请先添加产品信息', |
| | | type: 'warning', |
| | | message: "请先添加产品信息", |
| | | type: "warning", |
| | | }); |
| | | return; |
| | | } |
| | |
| | | .filter(node => node.userId) |
| | | .map(node => node.userId) |
| | | .join(","); |
| | | |
| | | |
| | | let params = { |
| | | productData: proxy.HaveJson(productData.value), |
| | | supplierId: form.value.supplierId, |
| | |
| | | approveUserIds: approveUserIds, |
| | | templateName: templateName.value.trim(), |
| | | }; |
| | | console.log("template params ===>", params, "currentTemplateId:", currentTemplateId.value); |
| | | console.log( |
| | | "template params ===>", |
| | | params, |
| | | "currentTemplateId:", |
| | | currentTemplateId.value |
| | | ); |
| | | |
| | | // 如果 currentTemplateId 有值,说明当前是“编辑已有模板” → 调用更新接口 |
| | | // 否则为“新建模板” → 调用新增接口 |
| | |
| | | ...params, |
| | | }); |
| | | } else { |
| | | res = await addPurchaseTemplate(params); |
| | | res = await addPurchaseTemplate({ |
| | | ...params, |
| | | templateType: currentSupplierType.value, |
| | | }); |
| | | } |
| | | |
| | | if (res && res.code === 200) { |
| | |
| | | }; |
| | | // 子表合计方法 |
| | | const summarizeChildrenTable = param => { |
| | | return proxy.summarizeTable( |
| | | param, |
| | | [ |
| | | // 检查是否有数据,以及数据的供应商类型 |
| | | const hasData = param && param.data && param.data.length > 0; |
| | | const supplierType = hasData ? param.data[0].supplierType : null; |
| | | |
| | | // 根据供应商类型确定要合计的字段 |
| | | const fields = [ |
| | | "ticketsNum", |
| | | "ticketsAmount", |
| | | "futureTickets", |
| | | "futureTicketsAmount", |
| | | ]; |
| | | |
| | | if (supplierType === 1) { |
| | | // 对公供应商 |
| | | fields.unshift( |
| | | "taxInclusiveUnitPrice", |
| | | "taxInclusiveTotalPrice", |
| | | "taxExclusiveTotalPrice", |
| | | "ticketsNum", |
| | | "ticketsAmount", |
| | | "futureTickets", |
| | | "futureTicketsAmount", |
| | | ], |
| | | { |
| | | ticketsNum: { noDecimal: true }, // 不保留小数 |
| | | futureTickets: { noDecimal: true }, // 不保留小数 |
| | | } |
| | | ); |
| | | "taxExclusiveTotalPrice" |
| | | ); |
| | | } else if (supplierType === 2) { |
| | | // 对私供应商 |
| | | fields.unshift("unitPrice", "totalPrice"); |
| | | } |
| | | |
| | | return proxy.summarizeTable(param, fields, { |
| | | ticketsNum: { noDecimal: true }, // 不保留小数 |
| | | futureTickets: { noDecimal: true }, // 不保留小数 |
| | | }); |
| | | }; |
| | | const paginationChange = obj => { |
| | | page.current = obj.page; |
| | |
| | | const res = await productList({ salesLedgerId: row.id, type: 2 }); |
| | | const index = tableData.value.findIndex(item => item.id === row.id); |
| | | if (index > -1) { |
| | | tableData.value[index].children = res.data || []; |
| | | // 为子表格数据添加供应商类型信息 |
| | | const children = (res.data || []).map(item => ({ |
| | | ...item, |
| | | supplierType: row.supplierType, // 从父行获取供应商类型 |
| | | })); |
| | | tableData.value[index].children = children; |
| | | expandedRowKeys.value.push(row.id); |
| | | } |
| | | } catch (error) { |
| | |
| | | }; |
| | | // 子表合计方法 |
| | | const summarizeProTable = param => { |
| | | return proxy.summarizeTable(param, [ |
| | | "taxInclusiveUnitPrice", |
| | | "taxInclusiveTotalPrice", |
| | | "taxExclusiveTotalPrice", |
| | | ]); |
| | | const fields = []; |
| | | if (currentSupplierType.value === 1) { |
| | | fields.push( |
| | | "taxInclusiveUnitPrice", |
| | | "taxInclusiveTotalPrice", |
| | | "taxExclusiveTotalPrice" |
| | | ); |
| | | } else if (currentSupplierType.value === 2) { |
| | | fields.push("unitPrice", "totalPrice"); |
| | | } |
| | | return proxy.summarizeTable(param, fields); |
| | | }; |
| | | // 打开弹框 |
| | | const openForm = async (type, row) => { |
| | |
| | | return; |
| | | } |
| | | } |
| | | |
| | | await getTemplateList(); |
| | | currentSupplierType.value = null; |
| | | |
| | | operationType.value = type; |
| | | form.value = {}; |
| | | productData.value = []; |
| | |
| | | form.value.entryDate = getCurrentDate(); |
| | | |
| | | if (type === "add") { |
| | | await getTemplateList(); |
| | | // 新增时生成采购合同号 |
| | | try { |
| | | const purchaseNoRes = await createPurchaseNo(); |
| | |
| | | const approverIds = purchaseRes.approveUserIds.split(","); |
| | | approverNodes.value = approverIds.map((id, index) => ({ |
| | | id: index + 1, |
| | | userId: Number(id) |
| | | userId: Number(id), |
| | | })); |
| | | nextApproverId = approverIds.length + 1; |
| | | } |
| | | // 设置当前供应商类型 |
| | | if (form.value.supplierId) { |
| | | handleSupplierChange(form.value.supplierId); |
| | | } |
| | | } catch (error) { |
| | | console.error("加载采购台账数据失败:", error); |
| | |
| | | proxy.$modal.msgError("请为所有审批节点选择审批人!"); |
| | | return; |
| | | } |
| | | const approveUserIds = approverNodes.value.map(node => node.userId).join(","); |
| | | |
| | | const approveUserIds = approverNodes.value |
| | | .map(node => node.userId) |
| | | .join(","); |
| | | |
| | | if (productData.value.length > 0) { |
| | | // 新增时,需要从每个产品对象中删除 id 字段 |
| | | let processedProductData = productData.value; |
| | |
| | | } |
| | | |
| | | // 新增时不传递id |
| | | const submitData = { ...form.value }; |
| | | const submitData = { |
| | | ...form.value, |
| | | purchaseType: currentSupplierType.value, |
| | | }; |
| | | if (operationType.value === "add") { |
| | | delete submitData.id; |
| | | } |
| | |
| | | const openProductForm = async (type, row, index) => { |
| | | productOperationType.value = type; |
| | | productOperationIndex.value = index; |
| | | productForm.value = {}; |
| | | productForm.value = { |
| | | productId: "", |
| | | productCategory: "", |
| | | productModelId: "", |
| | | specificationModel: "", |
| | | unit: "", |
| | | quantity: "", |
| | | // 对公字段 |
| | | taxInclusiveUnitPrice: "", |
| | | taxRate: "", |
| | | taxInclusiveTotalPrice: "", |
| | | taxExclusiveTotalPrice: "", |
| | | invoiceType: "", |
| | | // 对私字段 |
| | | unitPrice: "", |
| | | totalPrice: "", |
| | | // 公共字段 |
| | | warnNum: "", |
| | | isChecked: true, |
| | | }; |
| | | 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 nodes[i].value; |
| | | } |
| | | if (nodes[i].children && nodes[i].children.length > 0) { |
| | | const found = findProductIdByCategory(nodes[i].children, categoryName); |
| | | const found = findProductIdByCategory( |
| | | nodes[i].children, |
| | | categoryName |
| | | ); |
| | | if (found) return found; |
| | | } |
| | | } |
| | | return null; |
| | | }; |
| | | |
| | | const productId = findProductIdByCategory(productOptions.value, productForm.value.productCategory); |
| | | |
| | | 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) { |
| | | if ( |
| | | productForm.value.specificationModel && |
| | | modelOptions.value.length > 0 |
| | | ) { |
| | | const modelItem = modelOptions.value.find( |
| | | item => item.model === productForm.value.specificationModel |
| | | ); |
| | |
| | | } 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(); |
| | | } |
| | |
| | | }); |
| | | }; |
| | | const submitProductEdit = () => { |
| | | productForm.value.salesLedgerId = currentId.value; |
| | | productForm.value.type = 2; |
| | | addOrUpdateSalesLedgerProduct(productForm.value).then(res => { |
| | | proxy.$modal.msgSuccess("提交成功"); |
| | | closeProductDia(); |
| | | getPurchaseById({ id: currentId.value, type: 2 }).then(res => { |
| | | productData.value = res.productData; |
| | | }); |
| | | }); |
| | | // 直接修改本地数据,不再调用接口 |
| | | if (productOperationType.value === "add") { |
| | | // 新增产品 |
| | | productData.value.push({ ...productForm.value }); |
| | | } else if (productOperationType.value === "edit") { |
| | | // 编辑产品 |
| | | if ( |
| | | productOperationIndex.value !== "" && |
| | | productOperationIndex.value !== null |
| | | ) { |
| | | productData.value[productOperationIndex.value] = { ...productForm.value }; |
| | | } |
| | | } |
| | | proxy.$modal.msgSuccess("操作成功"); |
| | | closeProductDia(); |
| | | }; |
| | | // 删除产品 |
| | | const deleteProduct = () => { |
| | |
| | | proxy.$modal.msgWarning("请选择数据"); |
| | | return; |
| | | } |
| | | if (operationType.value === "add") { |
| | | productSelectedRows.value.forEach(selectedRow => { |
| | | const index = productData.value.findIndex( |
| | | product => product.id === selectedRow.id |
| | | ); |
| | | if (index !== -1) { |
| | | productData.value.splice(index, 1); |
| | | } |
| | | }); |
| | | } else { |
| | | let ids = []; |
| | | if (productSelectedRows.value.length > 0) { |
| | | ids = productSelectedRows.value.map(item => item.id); |
| | | } |
| | | ElMessageBox.confirm("选中的内容将被删除,是否确认删除?", "导出", { |
| | | confirmButtonText: "确认", |
| | | cancelButtonText: "取消", |
| | | type: "warning", |
| | | }) |
| | | .then(() => { |
| | | delProduct(ids).then(res => { |
| | | proxy.$modal.msgSuccess("删除成功"); |
| | | closeProductDia(); |
| | | getPurchaseById({ id: currentId.value, type: 2 }).then( |
| | | res => { |
| | | productData.value = res.productData; |
| | | } |
| | | ); |
| | | }); |
| | | }) |
| | | .catch(() => { |
| | | proxy.$modal.msg("已取消"); |
| | | // 直接从本地数据中删除,不再调用接口 |
| | | ElMessageBox.confirm("选中的内容将被删除,是否确认删除?", "导出", { |
| | | confirmButtonText: "确认", |
| | | cancelButtonText: "取消", |
| | | type: "warning", |
| | | }) |
| | | .then(() => { |
| | | productSelectedRows.value.forEach(selectedRow => { |
| | | const index = productData.value.findIndex( |
| | | product => product.id === selectedRow.id |
| | | ); |
| | | if (index !== -1) { |
| | | productData.value.splice(index, 1); |
| | | } |
| | | }); |
| | | } |
| | | proxy.$modal.msgSuccess("删除成功"); |
| | | closeProductDia(); |
| | | }) |
| | | .catch(() => { |
| | | proxy.$modal.msg("已取消"); |
| | | }); |
| | | }; |
| | | // 关闭产品弹框 |
| | | const closeProductDia = () => { |
| | |
| | | } |
| | | } |
| | | }; |
| | | |
| | | // 对私供应商的价格计算 |
| | | const mathNumPrivate = () => { |
| | | const { unitPrice, quantity } = productForm.value; |
| | | if (unitPrice && quantity) { |
| | | productForm.value.totalPrice = (unitPrice * quantity).toFixed(2); |
| | | } |
| | | }; |
| | | |
| | | // 对私供应商的反向价格计算 |
| | | const reverseMathNumPrivate = type => { |
| | | const { unitPrice, quantity, totalPrice } = productForm.value; |
| | | if (type === "totalPrice") { |
| | | if (quantity) { |
| | | productForm.value.unitPrice = (totalPrice / quantity).toFixed(2); |
| | | } else if (unitPrice) { |
| | | productForm.value.quantity = (totalPrice / unitPrice).toFixed(2); |
| | | } |
| | | } |
| | | }; |
| | | |
| | | // 销售合同选择改变方法 |
| | | const salesLedgerChange = async row => { |
| | | console.log("row", row); |
| | |
| | | |
| | | // 获取模板信息 |
| | | const getTemplateList = async () => { |
| | | let res = await getPurchaseTemplateList(); |
| | | if (res && res.code === 200 && Array.isArray(res.data)) { |
| | | templateList.value = res.data; |
| | | console.log("currentSupplierType.value", currentSupplierType.value); |
| | | if (currentSupplierType.value) { |
| | | let res = await getPurchaseTemplateList({ |
| | | templateType: currentSupplierType.value, |
| | | }); |
| | | if (res && res.code === 200 && Array.isArray(res.data)) { |
| | | templateList.value = res.data; |
| | | } |
| | | } else { |
| | | templateList.value = []; |
| | | } |
| | | }; |
| | | |
| | | // 删除模板 |
| | | const handleDeleteTemplate = async (item) => { |
| | | const handleDeleteTemplate = async item => { |
| | | if (!item.id) { |
| | | 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; |