| | |
| | | <div> |
| | | <el-dialog v-model="dialogVisible" |
| | | title="领料台账" |
| | | width="1200px" |
| | | width="1400px" |
| | | @close="handleClose"> |
| | | <div class="material-toolbar"> |
| | | <el-button type="primary" |
| | |
| | | </el-select> |
| | | </template> |
| | | </el-table-column> |
| | | <el-table-column label="库存数量" |
| | | min-width="120"> |
| | | <template #default="{ row }"> |
| | | <span :class="{ 'text-danger': isStockInsufficient(row) }"> |
| | | {{ row.stockQuantity ?? '-' }} |
| | | </span> |
| | | </template> |
| | | </el-table-column> |
| | | <el-table-column label="需求数量" |
| | | min-width="120"> |
| | | <template #default="{ row }"> |
| | | <span v-if="row.bom === true">{{ row.demandedQuantity ?? "-" }}</span> |
| | | <span v-if="row.bom === true" :class="{ 'text-danger': isStockInsufficient(row) }">{{ row.demandedQuantity ?? "-" }}</span> |
| | | <el-input-number v-else |
| | | v-model="row.demandedQuantity" |
| | | :min="0" |
| | |
| | | :step="1" |
| | | controls-position="right" |
| | | style="width: 100%;" |
| | | :class="{ 'is-stock-insufficient': isStockInsufficient(row) }" |
| | | @change="val => handleRequiredQtyChange(row, val)" /> |
| | | </template> |
| | | </el-table-column> |
| | |
| | | </el-table> |
| | | <template #footer> |
| | | <span class="dialog-footer"> |
| | | <el-button v-if="hasInsufficientStock" |
| | | type="warning" |
| | | @click="openPurchaseRequestDialog">采购申请</el-button> |
| | | <el-button type="primary" |
| | | :loading="materialSaving" |
| | | :disabled="isSaveDisabled" |
| | |
| | | <ProductSelectDialog v-model="materialProductDialogVisible" |
| | | @confirm="handleMaterialProductConfirm" |
| | | single /> |
| | | <PurchaseRequestDialog v-model="purchaseRequestDialogVisible" |
| | | :insufficient-items="insufficientStockItems" |
| | | :order-row="props.orderRow" |
| | | @saved="handlePurchaseRequestSaved" /> |
| | | <!-- request-url="/stockInventory/rawMaterials" --> |
| | | </div> |
| | | </template> |
| | |
| | | import { computed, ref, watch } from "vue"; |
| | | import { ElMessage } from "element-plus"; |
| | | import ProductSelectDialog from "@/views/basicData/product/ProductSelectDialog.vue"; |
| | | import PurchaseRequestDialog from "./PurchaseRequestDialog.vue"; |
| | | import { |
| | | findProductProcessRouteItemList, |
| | | listMain, |
| | | } from "@/api/productionManagement/productProcessRoute.js"; |
| | | import { |
| | | listMaterialPickingDetail, |
| | | listMaterialPickingBom, |
| | | listMaterialPickingLedger, |
| | | saveMaterialPickingLedger, |
| | | updateMaterialPickingLedger, |
| | | } from "@/api/productionManagement/productionOrder.js"; |
| | | import { queryList2 } from "@/api/productionManagement/productStructure.js"; |
| | | |
| | | |
| | | const props = defineProps({ |
| | | modelValue: { type: Boolean, default: false }, |
| | |
| | | const materialTableLoading = ref(false); |
| | | const materialSaving = ref(false); |
| | | const materialTableData = ref([]); |
| | | const purchaseRequestDialogVisible = ref(false); |
| | | |
| | | const isSaveDisabled = computed(() => { |
| | | if (materialTableData.value.length === 0) return true; |
| | |
| | | }); |
| | | }); |
| | | |
| | | // 判断库存是否不足 |
| | | const isStockInsufficient = (row) => { |
| | | const stockQuantity = Number(row.stockQuantity ?? 0); |
| | | const demandedQty = Number(row.demandedQuantity ?? 0); |
| | | return demandedQty > 0 && stockQuantity > 0 && demandedQty > stockQuantity; |
| | | }; |
| | | |
| | | // 库存不足的行 |
| | | const insufficientStockItems = computed(() => { |
| | | return materialTableData.value.filter(row => isStockInsufficient(row)); |
| | | }); |
| | | |
| | | // 是否有库存不足 |
| | | const hasInsufficientStock = computed(() => { |
| | | return insufficientStockItems.value.length > 0; |
| | | }); |
| | | |
| | | const processOptions = ref([]); |
| | | const currentMaterialSelectRowIndex = ref(-1); |
| | | let materialTempId = 0; |
| | |
| | | : row.batchNo |
| | | : [], |
| | | batchNoList: row.batchNoList || [], |
| | | stockQuantity: row.stockQuantity ?? row.stockQty ?? null, |
| | | }); |
| | | |
| | | const getProcessOptions = async () => { |
| | |
| | | materialTableData.value = []; |
| | | await getProcessOptions(); |
| | | try { |
| | | const detailRes = await listMaterialPickingDetail(props.orderRow.id); |
| | | const detailList = Array.isArray(detailRes?.data) |
| | | ? detailRes.data |
| | | : detailRes?.data?.records || []; |
| | | if (detailList.length > 0) { |
| | | isDetail.value = true; |
| | | materialTableData.value = detailList.map(item => createMaterialRow(item)); |
| | | return; |
| | | } else { |
| | | // 直接调用listMaterialPickingBom接口获取库存数量 |
| | | const bomRes = await listMaterialPickingBom(props.orderRow.id); |
| | | const bomList = Array.isArray(bomRes?.data) |
| | | ? bomRes.data |
| | | : bomRes?.data?.records || []; |
| | | if (bomList.length > 0) { |
| | | isDetail.value = false; |
| | | const bomRes = await listMaterialPickingBom(props.orderRow.id); |
| | | const bomList = Array.isArray(bomRes?.data) |
| | | ? bomRes.data |
| | | : bomRes?.data?.records || []; |
| | | materialTableData.value = bomList.map(item => createMaterialRow(item)); |
| | | return; |
| | | } |
| | | } finally { |
| | | materialTableLoading.value = false; |
| | |
| | | materialProductDialogVisible.value = true; |
| | | }; |
| | | |
| | | const handleMaterialProductConfirm = products => { |
| | | const handleMaterialProductConfirm = async (products) => { |
| | | console.log(products, "products"); |
| | | |
| | | if (!products || products.length === 0) return; |
| | |
| | | materialSaving.value = false; |
| | | } |
| | | }; |
| | | |
| | | // 打开采购申请对话框 |
| | | const openPurchaseRequestDialog = () => { |
| | | purchaseRequestDialogVisible.value = true; |
| | | }; |
| | | |
| | | // 采购申请保存回调 |
| | | const handlePurchaseRequestSaved = () => { |
| | | // 采购申请保存成功后刷新数据 |
| | | loadMaterialData(); |
| | | }; |
| | | </script> |
| | | |
| | | <style scoped lang="scss"> |
| | |
| | | margin-bottom: 12px; |
| | | text-align: right; |
| | | } |
| | | |
| | | .text-danger { |
| | | color: #f56c6c; |
| | | font-weight: bold; |
| | | } |
| | | |
| | | :deep(.is-stock-insufficient) { |
| | | .el-input__wrapper { |
| | | box-shadow: 0 0 0 1px #f56c6c inset; |
| | | } |
| | | } |
| | | </style> |