| src/views/inventoryManagement/receiptManagement/index.vue | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 | |
| src/views/inventoryManagement/stockManagement/index.vue | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 | |
| src/views/procurementManagement/procurementLedger/index.vue | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 | 
src/views/inventoryManagement/receiptManagement/index.vue
@@ -54,22 +54,26 @@ <el-dialog v-model="dialogFormVisible" :title="operationType === 'add' ? '新增入库' : '编辑入库'" width="70%" @close="closeDia"> <el-form :model="form" label-width="140px" label-position="top" :rules="rules" ref="formRef"> <el-form-item label="采购订单号" prop="salesContractNo"> <el-input <el-form-item label="采购订单号" prop="purchaseContractNumber"> <el-select v-model="form.purchaseContractNumber" placeholder="请输入合同号" placeholder="请选择采购订单号" clearable @change="searchByContractNo" filterable remote :remote-method="loadPurchaseOptions" :loading="loadingPurchaseOptions" @change="handlePurchaseChange" :disabled="operationType === 'edit'" style="width: 100%" > <template #append> <el-button icon="Search" @click="searchByContractNo" :loading="loadingProducts" /> </template> </el-input> <el-option v-for="item in purchaseOptions" :key="item.purchaseContractNumber" :label="formatPurchaseOption(item)" :value="item.purchaseContractNumber" /> </el-select> </el-form-item> <el-table :data="productList" @@ -92,7 +96,7 @@ <el-table-column label="待入库数量" prop="quantity0" width="100" /> <el-table-column label="本次入库数量" prop="quantityStock" width="150"> <template #default="scope"> <el-input-number :step="0.01" :min="0" style="width: 100%" v-model="scope.row.quantityStock" :max="scope.row.quantity0" /> <el-input-number :step="0.01" :min="0" style="width: 100%" v-model="scope.row.quantityStock" /> </template> </el-table-column> <el-table-column label="税率(%)" prop="taxRate" width="120" /> @@ -128,7 +132,7 @@ <script setup> import pagination from '@/components/PIMTable/Pagination.vue' import { ref } from 'vue' import { ref, reactive, toRefs, onMounted, getCurrentInstance } from 'vue' import { ElMessageBox } from "element-plus"; import useUserStore from '@/store/modules/user' import { @@ -138,6 +142,7 @@ delStockIn, selectProductRecordListByPuechaserId } from "@/api/inventoryManagement/stockIn.js"; import { purchaseListPage } from "@/api/procurementManagement/procurementLedger.js"; const userStore = useUserStore() const { proxy } = getCurrentInstance() @@ -145,6 +150,9 @@ const tableData = ref([]) const selectedRows = ref([]) const userList = ref([]) const purchaseOptions = ref([]) const loadingPurchaseOptions = ref(false) const loading = ref(false); @@ -188,6 +196,75 @@ }) const { searchForm, form, rules } = toRefs(data) const formatPurchaseOption = (item = {}) => { const contract = item.purchaseContractNumber || '--'; const supplier = item.supplierName ? ` · ${item.supplierName}` : ''; return `${contract}${supplier}`; }; const loadPurchaseOptions = async (keyword = '') => { try { loadingPurchaseOptions.value = true; const res = await purchaseListPage({ current: -1, size: -1, purchaseContractNumber: keyword, }); const records = res.data?.records || []; purchaseOptions.value = records; if ( form.value.purchaseContractNumber && !purchaseOptions.value.find( (item) => item.purchaseContractNumber === form.value.purchaseContractNumber ) ) { purchaseOptions.value.push({ purchaseContractNumber: form.value.purchaseContractNumber, supplierName: form.value.supplierName, supplierId: form.value.supplierId, }); } } finally { loadingPurchaseOptions.value = false; } }; const handlePurchaseChange = (value) => { form.value.purchaseContractNumber = value || ''; const matched = purchaseOptions.value.find( (item) => item.purchaseContractNumber === value ); if (matched) { form.value.supplierName = matched.supplierName || form.value.supplierName; form.value.supplierId = matched.supplierId || form.value.supplierId; } if (!value) { productList.value = []; return; } fetchProductsByContract(); }; const exceedsAddLimit = (product) => { const stock = Number(product?.quantityStock ?? 0); const waiting = Number(product?.quantity0 ?? 0); if (!Number.isFinite(stock) || !Number.isFinite(waiting)) { return false; } return stock > waiting; }; const exceedsEditLimit = (product) => { const stock = Number(product?.quantityStock ?? 0); const waiting = Number(product?.quantity0 ?? 0); const original = Number(product?.originalQuantityStock ?? 0); if (!Number.isFinite(stock) || !Number.isFinite(waiting) || !Number.isFinite(original)) { return false; } return stock > waiting + original; }; const formattedNumber = (row, column, cellValue) => { return parseFloat(cellValue).toFixed(2); }; // 查询列表 /** 搜索按钮操作 */ const handleQuery = () => { @@ -214,10 +291,10 @@ // 调用selectProductRecordListByPuechaserId这个方法根据合同查询到id,再调用getProductRecordByhetong这个方法根据id查询到产品订单记录 // 新增根据合同号查询产品记录的方法 const searchByContractNo = async () => const fetchProductsByContract = async () => { if (!form.value.purchaseContractNumber) { proxy.$modal.msgWarning('请输入合同号') proxy.$modal.msgWarning('请选择合同号') return } try { @@ -235,7 +312,8 @@ // 处理产品数据,添加本次入库数量字段 productList.value = productRes.data.map(item => ({ ...item, quantityStock: 0 // 初始化本次入库数量为0 quantityStock: 0, originalQuantityStock: Number(item.quantityStock ?? item.inboundQuantity ?? 0), })) } catch (error) { console.error('查询产品记录失败:', error) @@ -252,6 +330,7 @@ operationType.value = type dialogFormVisible.value = true selectedRows.value = [] await loadPurchaseOptions(); if (type === 'add') { // 新增时初始化表单 @@ -277,10 +356,11 @@ purchaseContractNumber: form.value.purchaseContractNumber, id: row.id }); productList.value = res.data.map(item => ({ ...item, quantityStock: row.inboundNum // 如果已有入库数量则保留 })) productList.value = res.data.map(item => ({ ...item, quantityStock: Number(item.quantityStock ?? item.inboundQuantity ?? row.inboundNum ?? 0), originalQuantityStock: Number(item.quantityStock ?? item.inboundQuantity ?? row.inboundNum ?? 0), })) selectedRows.value = productList.value } catch (error) { console.error('加载产品失败:', error) @@ -293,8 +373,22 @@ } const updatePro = async () => { // 准备提交数据 // 准备提交数据 - 修改为后端需要的格式 // 准备提交数据 // 准备提交数据 - 修改为后端需要的格式 if (selectedRows.value.length === 0) { proxy.$modal.msgWarning('请先选择产品'); return; } const target = selectedRows.value[0]; const stock = Number(target?.quantityStock ?? 0); if (!Number.isFinite(stock) || stock <= 0) { proxy.$modal.msgWarning('请填写有效的入库数量'); return; } if (exceedsEditLimit(target)) { proxy.$modal.msgError('本次入库数量不能超过原入库数量与待入库数量之和'); return; } const stockInData = { id: selectedRows.value[0].recordId, quantityStock: Number(selectedRows.value[0].quantityStock),// 使用新格式化函数 @@ -309,7 +403,7 @@ const submitForm = async () => { // 验证至少选择了一个产品 if (selectedRows.value.length === 0) { proxy.$modal.msgError('请先查询并选择产品') proxy.$modal.msgWarning('请先选择采购合同并选择产品') return } if(operationType.value !== 'add'){ @@ -319,29 +413,31 @@ try { await proxy.$refs.formRef.validate() // 验证入库数量 const invalidProducts = selectedRows.value.filter( product => product.quantityStock <= 0 || product.quantityStock > product.quantity0 ) const invalidProducts = selectedRows.value.filter((product) => { const stock = Number(product?.quantityStock ?? 0); if (!Number.isFinite(stock) || stock <= 0) { return true; } return exceedsAddLimit(product); }) if (invalidProducts.length > 0) { proxy.$modal.msgError('请为所有产品输入有效的入库数量') proxy.$modal.msgError('本次入库数量需大于0,且不能超过待入库数量') return } // 准备提交数据 // 准备提交数据 - 修改为后端需要的格式 const stockInData = { // 入库单基本信息 ...form.value, inboundTime: formatDateTime(form.value.inboundTime), nickName: userStore.nickName,// 使用新格式化函数 nickName: userStore.nickName, details: selectedRows.value.map(product => ({ id: product.id, // id: product.salesLedgerProductId, inboundQuantity: Number(product.quantityStock) })), }; console.log('准备提交的数据:', JSON.parse(JSON.stringify(stockInData))); // 调用API loading.value = true await addSutockIn(stockInData) @@ -370,7 +466,6 @@ const handleSelectionChange = (selection) => { // 过滤掉子数据 selectedRows.value = selection.filter(item => item.id); console.log('selection', selectedRows.value) } const expandedRowKeys = ref([]) src/views/inventoryManagement/stockManagement/index.vue
@@ -26,6 +26,7 @@ <div class="table_list"> <el-table :data="tableData" border v-loading="tableLoading" @selection-change="handleSelectionChange" :expand-row-keys="expandedRowKeys" :row-key="row => row.id" show-summary style="width: 100%" :row-class-name="tableRowClassName" :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" /> @@ -35,7 +36,7 @@ <el-table-column label="规格型号" prop="specificationModel" width="200" show-overflow-tooltip /> <el-table-column label="单位" prop="unit" width="80" show-overflow-tooltip /> <el-table-column label="库存数量" prop="inboundNum0" width="100" show-overflow-tooltip /> <el-table-column label="最低库存数量" prop="minStock" width="130" show-overflow-tooltip /> <el-table-column label="库存预警数量" prop="warnNum" width="130" show-overflow-tooltip /> <el-table-column label="含税单价" prop="taxInclusiveUnitPrice" width="100" show-overflow-tooltip /> <el-table-column label="含税总价" prop="taxInclusiveTotalPrice" width="100" show-overflow-tooltip /> <el-table-column label="税率(%)" prop="taxRate" width="100" show-overflow-tooltip /> @@ -61,7 +62,7 @@ </el-col> <el-col :span="12"> <el-form-item label="产品大类:" prop="productId"> <el-select disabled v-model="form.productCategory" placeholder="请选择" clearable filterable @change="handleProductChange"> <el-select disabled v-model="form.productCategory" placeholder="请选择" clearable filterable> <el-option v-for="item in productList" :key="item.id" :label="item.productName" :value="item.productName" /> </el-select> @@ -71,8 +72,7 @@ <el-row :gutter="30"> <el-col :span="12"> <el-form-item label="规格型号:" prop="productManageId"> <el-select disabled v-model="form.specificationModel" placeholder="请先选择产品大类" clearable filterable :disabled="!form.productCategory" @change="handleModelChange"> <el-select disabled v-model="form.specificationModel" placeholder="请先选择产品大类" clearable filterable :disabled="!form.productCategory"> <el-option v-for="item in productModelList" :key="item.id" :label="item.model" :value="item.id" /> </el-select> @@ -132,11 +132,11 @@ </el-select> </el-form-item> </el-col> <el-col :span="12"> <el-form-item label="最低库存:" prop="minStock"> <el-input v-model="form.minStock" placeholder="请输入最低库存" clearable /> </el-form-item> </el-col> <!-- <el-col :span="12">--> <!-- <el-form-item label="库存预警数量:" prop="warnNum">--> <!-- <el-input v-model="form.warnNum" placeholder="请输入最低库存" clearable />--> <!-- </el-form-item>--> <!-- </el-col>--> </el-row> </el-form> <template #footer> @@ -151,19 +151,17 @@ <script setup> import pagination from '@/components/PIMTable/Pagination.vue' import { ref } from 'vue' import { ref, reactive, toRefs, onMounted, getCurrentInstance } from 'vue' import { ElMessageBox } from "element-plus"; import useUserStore from '@/store/modules/user' import { userListNoPageByTenantId } from "@/api/system/user.js"; import { productTreeList,modelList } from "@/api/basicData/product.js" import { getStockManagePage , updateStockManage, getStockManagePage, delStockManage, exportStockManage } from "@/api/inventoryManagement/stockManage.js"; import { updateManagement,addSutockIn,selectProductRecordListByPuechaserId,updateStockIn updateManagement,updateStockIn } from "@/api/inventoryManagement/stockIn.js"; @@ -212,7 +210,7 @@ inboundBatch: '', stockQuantity: '', boundTime: '', minStock: '', // 新增最低库存字段 warnNum: '', // 新增最低库存字段 salesLedgerProductId: null, }, rules: { @@ -228,7 +226,7 @@ boundTime: [{ required: true, message: '请选择库存时间', trigger: 'change' }], inboundTime: [{ required: true, message: '请选择入库时间', trigger: 'change' }], inboundPerson: [{ required: true, message: '请选择出库人', trigger: 'change' }], minStock: [{ required: true, message: '请输入最低库存', trigger: 'blur' }], warnNum: [{ required: true, message: '请输入最低库存', trigger: 'blur' }], } }) const { searchForm, form, rules } = toRefs(data) @@ -249,13 +247,9 @@ getStockManagePage({ ...searchForm.value, ...page }).then(res => { tableLoading.value = false tableData.value = res.data.records // console.log('res', res) // tableData.value.map(item => { // item.children = [] // }) total.value = res.data.total // 数据加载完成后检查库存 checkStockAndCreatePurchase(); // checkStockAndCreatePurchase(); }).catch(() => { tableLoading.value = false }) @@ -275,6 +269,16 @@ return proxy.summarizeTable(param, ['contractAmount', 'taxInclusiveTotalPrice', 'taxExclusiveTotalPrice']); }; // 表格行类名 const tableRowClassName = ({ row }) => { const stock = Number(row?.inboundNum0 ?? 0); const warn = Number(row?.warnNum ?? 0); if (!Number.isFinite(stock) || !Number.isFinite(warn)) { return ''; } return stock < warn ? 'row-low-stock' : ''; }; // 打开弹框 const openForm = async (type, row) => { operationType.value = type @@ -282,11 +286,6 @@ productData.value = [] let userLists = await userListNoPageByTenantId() userList.value = userLists.data // customerList().then(res => { // customerOption.value = res // }) // console.log('userStore.id', userStore.id) // form.value.entryPerson = userStore.id if (type === 'edit') { form.value = { ...row } productTreeList().then(res =>{ @@ -299,14 +298,6 @@ } }) }) // getSalesLedgerWithProducts({ id: row.id, type: 1 }).then(res => { // form.value.entryPerson = Number(res.entryPerson) // productData.value = form.value.productData // fileList.value = form.value.salesLedgerFiles // }) } form.value.entryDate = getCurrentDate() // 设置默认录入日期为当前日期 dialogFormVisible.value = true @@ -323,63 +314,33 @@ closeDia() getList() // 提交后检查库存并尝试创建请购单 checkStockAndCreatePurchase(); // checkStockAndCreatePurchase(); }) } }) } // const handList = () => { // selectProductRecordListByPuechaserId().then(res => { // productModelList.value = res.data.filter(item => item.productName === value) // console.log('productModelList.value', productModelList.value) // }) // } // 检查库存并创建请购单 const checkStockAndCreatePurchase = async () => { const stockList = tableData.value; // handList() for (const item of stockList) { if (item.inboundNum0 < item.minStock) { try { console.log('item', item) // const stockInData = { // nickName: userStore.nickName,// 使用新格式化函数 // details: [{ // id: item.salesLedgerProductId, // inboundQuantity: item.minStock - item.inboundNum0 // }] // }; const stockInData = { id: item.id, quantityStock: item.minStock + item.totalInboundNum,// 使用新格式化函数 }; console.log('准备提交的数据:', JSON.parse(JSON.stringify(stockInData))); loading.value = true // await addSutockIn(stockInData) await updateStockIn(stockInData) proxy.$modal.msgSuccess(`产品 ${item.productCategory} 修改入库成功`) loading.value = false // // 生成请购单 // const createRes = await createPurchaseRequest({ // productId: item.productId, // requiredQuantity: item.minStock - item.inboundNum0, // supplierId: item.supplierId // }); // if (createRes.code === 200) { // // 流转请购单到采购模块 // await transferPurchaseRequest({ requestId: createRes.data.id }); // proxy.$modal.msgSuccess(`产品 ${item.productName} 请购单已生成并流转`); // } } catch (error) { proxy.$modal.msgError(`产品 ${item.productCategory} 生成请购单失败,请手动处理`); } } } }; // const checkStockAndCreatePurchase = async () => { // const stockList = tableData.value; // // handList() // for (const item of stockList) { // if (item.inboundNum0 < item.warnNum) { // try { // const stockInData = { // id: item.id, // quantityStock: item.warnNum + item.totalInboundNum,// 使用新格式化函数 // }; // loading.value = true // await updateStockIn(stockInData) // proxy.$modal.msgSuccess(`产品 ${item.productCategory} 修改入库成功`) // loading.value = false // } catch (error) { // proxy.$modal.msgError(`产品 ${item.productCategory} 生成请购单失败,请手动处理`); // // } // } // } // }; // 关闭弹框 const closeDia = () => { proxy.resetForm("formRef") @@ -442,15 +403,24 @@ } onMounted(() => { getList() checkStockAndCreatePurchase(); // checkStockAndCreatePurchase(); // 每小时检查一次库存 const intervalId = setInterval(checkStockAndCreatePurchase, 60 * 60 * 1000); // const intervalId = setInterval(checkStockAndCreatePurchase, 60 * 60 * 1000); onUnmounted(() => { // 组件卸载时清除定时器 clearInterval(intervalId); }); // onUnmounted(() => { // // 组件卸载时清除定时器 // clearInterval(intervalId); // }); }) </script> <style scoped lang="scss"></style> <style scoped lang="scss"> :deep(.row-low-stock td) { background-color: #fde2e2; color: #c45656; } :deep(.row-low-stock:hover > td) { background-color: #fcd4d4; } </style> src/views/procurementManagement/procurementLedger/index.vue
@@ -318,6 +318,7 @@ <el-table-column label="规格型号" prop="specificationModel" /> <el-table-column label="单位" prop="unit" width="70" /> <el-table-column label="数量" prop="quantity" width="70" /> <el-table-column label="库存预警数量" prop="warnNum" width="120" show-overflow-tooltip /> <el-table-column label="税率(%)" prop="taxRate" width="80" /> <el-table-column label="含税单价(元)" @@ -539,6 +540,17 @@ </el-select> </el-form-item> </el-col> <el-col :span="12"> <el-form-item label="库存预警数量:" prop="warnNum"> <el-input-number v-model="productForm.warnNum" :precision="2" :step="0.1" clearable style="width: 100%" /> </el-form-item> </el-col> </el-row> </el-form> <template #footer> @@ -872,6 +884,7 @@ taxInclusiveTotalPrice: "", taxExclusiveTotalPrice: "", invoiceType: "", warnNum: "", }, productRules: { productId: [{ required: true, message: "请选择", trigger: "change" }], @@ -882,6 +895,7 @@ { required: true, message: "请输入", trigger: "blur" }, ], taxRate: [{ required: true, message: "请选择", trigger: "change" }], warnNum: [{ required: true, message: "请选择", trigger: "change" }], taxInclusiveTotalPrice: [ { required: true, message: "请输入", trigger: "blur" }, ],