<template>
|
<el-dialog v-model="dialogVisible"
|
title="补料"
|
width="1400px"
|
@close="handleClose">
|
<el-table v-loading="loading"
|
:data="tableData"
|
border
|
row-key="id">
|
<el-table-column label="工序名称"
|
prop="operationName"
|
min-width="140" />
|
<el-table-column label="原料名称"
|
prop="productName"
|
min-width="140" />
|
<el-table-column label="原料型号"
|
prop="model"
|
min-width="140" />
|
<el-table-column label="计量单位"
|
prop="unit"
|
width="100" />
|
<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="需求数量"
|
prop="demandedQuantity"
|
width="100" />
|
<el-table-column label="领用数量"
|
prop="pickQuantity"
|
width="100" />
|
<el-table-column label="已补数量"
|
prop="feedingQty"
|
width="100" />
|
<el-table-column label="补料数量"
|
min-width="150">
|
<template #default="{ row }">
|
<el-input-number v-model="row.newSupplementQty"
|
:min="0"
|
:precision="3"
|
:step="1"
|
controls-position="right"
|
placeholder="输入补料数量"
|
style="width: 100%;"
|
:class="{ 'is-stock-insufficient': isStockInsufficient(row) }" />
|
</template>
|
</el-table-column>
|
<el-table-column label="补料原因"
|
min-width="200">
|
<template #default="{ row }">
|
<el-input v-model="row.newSupplementReason"
|
placeholder="输入补料原因"
|
maxlength="200"
|
show-word-limit />
|
</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="submitting"
|
@click="handleSubmit">确 定</el-button>
|
<el-button @click="dialogVisible = false">取 消</el-button>
|
</span>
|
</template>
|
</el-dialog>
|
<PurchaseRequestDialog v-model="purchaseRequestDialogVisible"
|
:insufficient-items="insufficientStockItems"
|
:order-row="props.orderRow"
|
@saved="handlePurchaseRequestSaved" />
|
</template>
|
|
<script setup>
|
import { computed, ref, watch } from "vue";
|
import { ElMessage } from "element-plus";
|
import PurchaseRequestDialog from "./PurchaseRequestDialog.vue";
|
import {
|
listMaterialPickingDetail,
|
updateMaterialPickingLedger,
|
listMaterialPickingBom,
|
} from "@/api/productionManagement/productionOrder.js";
|
|
const props = defineProps({
|
modelValue: { type: Boolean, default: false },
|
orderRow: { type: Object, default: null },
|
});
|
const emit = defineEmits(["update:modelValue", "saved"]);
|
|
const dialogVisible = computed({
|
get: () => props.modelValue,
|
set: val => emit("update:modelValue", val),
|
});
|
|
const loading = ref(false);
|
const submitting = ref(false);
|
const tableData = ref([]);
|
const purchaseRequestDialogVisible = ref(false);
|
|
// 判断库存是否不足
|
const isStockInsufficient = (row) => {
|
const stockQuantity = Number(row.stockQuantity ?? 0);
|
const supplementQty = Number(row.newSupplementQty ?? 0);
|
return supplementQty > 0 && stockQuantity > 0 && supplementQty > stockQuantity;
|
};
|
|
// 库存不足的行
|
const insufficientStockItems = computed(() => {
|
return tableData.value.filter(row => isStockInsufficient(row));
|
});
|
|
// 是否有库存不足
|
const hasInsufficientStock = computed(() => {
|
return insufficientStockItems.value.length > 0;
|
});
|
|
const loadData = async () => {
|
if (!props.orderRow?.id) return;
|
loading.value = true;
|
try {
|
// 获取物料明细
|
const res = await listMaterialPickingDetail(props.orderRow.id);
|
// 获取库存数量
|
const bomRes = await listMaterialPickingBom(props.orderRow.id);
|
const bomList = Array.isArray(bomRes?.data)
|
? bomRes.data
|
: bomRes?.data?.records || [];
|
// 创建库存数量映射
|
const stockMap = new Map();
|
bomList.forEach(item => {
|
const key = item.materialModelId || item.productModelId;
|
if (key) {
|
stockMap.set(key, item.stockQuantity ?? item.stockQty ?? 0);
|
}
|
});
|
// 合并库存数据
|
tableData.value = (res.data || []).map(item => ({
|
...item,
|
newSupplementQty: 0,
|
newSupplementReason: "",
|
stockQuantity: stockMap.get(item.productModelId) ?? null,
|
}));
|
} catch (e) {
|
console.error("获取物料明细失败:", e);
|
ElMessage.error("获取物料明细失败");
|
} finally {
|
loading.value = false;
|
}
|
};
|
|
watch(
|
() => dialogVisible.value,
|
visible => {
|
if (visible) {
|
loadData();
|
}
|
}
|
);
|
|
const handleClose = () => {
|
tableData.value = [];
|
};
|
|
const handleSubmit = async () => {
|
const supplementList = tableData.value.filter(
|
item => item.newSupplementQty > 0
|
);
|
if (supplementList.length === 0) {
|
ElMessage.warning("请至少输入一条补料数量");
|
return;
|
}
|
|
const invalidRow = supplementList.find(item => !item.newSupplementReason);
|
if (invalidRow) {
|
ElMessage.warning("请输入补料原因");
|
return;
|
}
|
|
submitting.value = true;
|
try {
|
await updateMaterialPickingLedger({
|
productionOrderId: props.orderRow.id,
|
productionOrderPickDto: tableData.value.map(item => ({
|
id: item.id,
|
technologyOperationId: item.technologyOperationId,
|
operationName: item.operationName,
|
bom: item.bom === true,
|
productModelId: item.productModelId,
|
demandedQuantity: item.demandedQuantity,
|
unit: item.unit,
|
pickQuantity: item.pickQuantity,
|
batchNo: item.batchNo,
|
feedingQuantity: item.newSupplementQty || 0,
|
feedingReason: item.newSupplementReason || "",
|
pickType: 2,
|
})),
|
});
|
ElMessage.success("补料成功");
|
dialogVisible.value = false;
|
emit("saved");
|
} catch (e) {
|
console.error("补料失败:", e);
|
ElMessage.error("补料失败");
|
} finally {
|
submitting.value = false;
|
}
|
};
|
|
// 打开采购申请对话框
|
const openPurchaseRequestDialog = () => {
|
purchaseRequestDialogVisible.value = true;
|
};
|
|
// 采购申请保存回调
|
const handlePurchaseRequestSaved = () => {
|
// 采购申请保存成功后刷新数据
|
loadData();
|
};
|
</script>
|
|
<style scoped lang="scss">
|
.text-danger {
|
color: #f56c6c;
|
font-weight: bold;
|
}
|
|
:deep(.is-stock-insufficient) {
|
.el-input__wrapper {
|
box-shadow: 0 0 0 1px #f56c6c inset;
|
}
|
}
|
</style>
|