<template>
|
<div>
|
<el-dialog v-model="dialogVisible"
|
title="领料详情"
|
width="1400px"
|
@close="handleClose">
|
<el-table v-loading="materialDetailLoading"
|
:data="materialDetailTableData"
|
border
|
row-key="id">
|
<el-table-column label="工序名称"
|
prop="operationName"
|
min-width="180" />
|
<el-table-column label="原料名称"
|
prop="productName"
|
min-width="160" />
|
<el-table-column label="原料型号"
|
prop="model"
|
min-width="180" />
|
<el-table-column label="批号"
|
prop="batchNo"
|
min-width="150" />
|
<el-table-column label="需求数量"
|
prop="demandedQuantity"
|
min-width="110" />
|
<el-table-column label="计量单位"
|
prop="unit"
|
width="100" />
|
<el-table-column label="领用数量"
|
prop="pickQuantity"
|
min-width="110" />
|
<el-table-column label="补料数量"
|
min-width="120">
|
<template #default="{ row }">
|
<el-button type="primary"
|
link
|
@click="handleViewSupplementRecord(row)">
|
{{ row.feedingQty ?? 0 }}
|
</el-button>
|
</template>
|
</el-table-column>
|
<el-table-column label="退料数量"
|
min-width="110">
|
<template #default="{ row }">
|
{{ row.returnQty ?? 0 }}
|
</template>
|
</el-table-column>
|
<el-table-column label="实际数量"
|
min-width="140">
|
<template #default="{ row }">
|
<el-input-number v-model="row.actualQty"
|
:min="0"
|
:precision="3"
|
:step="1"
|
controls-position="right"
|
placeholder="输入实际数量"
|
style="width: 100%;"
|
:disabled="row.returned || orderRow?.end"
|
@change="val => handleActualQtyChange(row, val)" />
|
</template>
|
</el-table-column>
|
</el-table>
|
<template #footer>
|
<span class="dialog-footer">
|
<el-button v-if="!orderRow?.end"
|
type="warning"
|
:loading="materialReturnConfirming"
|
:disabled="!canOpenReturnSummary"
|
@click="openReturnSummaryDialog">
|
退料确认
|
</el-button>
|
<el-button @click="dialogVisible = false">取消</el-button>
|
</span>
|
</template>
|
</el-dialog>
|
<el-dialog v-model="supplementRecordDialogVisible"
|
title="补料记录"
|
width="800px">
|
<el-table v-loading="supplementRecordLoading"
|
:data="supplementRecordTableData"
|
border
|
row-key="id">
|
<el-table-column label="补料数量"
|
prop="pickQuantity"
|
min-width="120" />
|
<el-table-column label="补料人"
|
prop="supplementUserName"
|
min-width="120" />
|
<el-table-column label="补料日期"
|
prop="supplementTime"
|
min-width="160" />
|
<el-table-column label="补料原因"
|
prop="feedingReason"
|
min-width="200" />
|
</el-table>
|
<template #footer>
|
<span class="dialog-footer">
|
<el-button @click="supplementRecordDialogVisible = false">关闭</el-button>
|
</span>
|
</template>
|
</el-dialog>
|
<el-dialog v-model="returnSummaryDialogVisible"
|
title="退料汇总确认"
|
width="900px">
|
<el-table :data="returnSummaryList"
|
border
|
row-key="summaryKey">
|
<el-table-column label="原料名称"
|
prop="materialName"
|
min-width="180" />
|
<el-table-column label="原料型号"
|
prop="materialModel"
|
min-width="180" />
|
<el-table-column label="计量单位"
|
prop="unit"
|
min-width="100" />
|
<el-table-column label="退料汇总数量"
|
prop="returnQtyTotal"
|
min-width="140" />
|
</el-table>
|
<template #footer>
|
<span class="dialog-footer">
|
<el-button type="primary"
|
:loading="materialReturnConfirming"
|
@click="handleReturnConfirm">确认提交</el-button>
|
<el-button @click="returnSummaryDialogVisible = false">取消</el-button>
|
</span>
|
</template>
|
</el-dialog>
|
</div>
|
</template>
|
|
<script setup>
|
import { computed, ref, watch } from "vue";
|
import { ElMessage } from "element-plus";
|
import {
|
listMaterialPickingDetail,
|
listMaterialSupplementRecord,
|
updateMaterialPickingLedger,
|
} from "@/api/productionManagement/productionOrder.js";
|
|
const props = defineProps({
|
modelValue: { type: Boolean, default: false },
|
orderRow: { type: Object, default: null },
|
});
|
const emit = defineEmits(["update:modelValue", "confirmed"]);
|
|
const dialogVisible = computed({
|
get: () => props.modelValue,
|
set: val => emit("update:modelValue", val),
|
});
|
|
const materialDetailLoading = ref(false);
|
const materialDetailTableData = ref([]);
|
const materialReturnConfirming = ref(false);
|
const supplementRecordDialogVisible = ref(false);
|
const supplementRecordLoading = ref(false);
|
const supplementRecordTableData = ref([]);
|
const returnSummaryDialogVisible = ref(false);
|
const returnSummaryList = ref([]);
|
const calcReturnQty = item =>
|
Number(item.pickQuantity || 0) +
|
Number(item.feedingQty || 0) -
|
Number(item.actualQty || 0);
|
const canOpenReturnSummary = computed(() =>
|
materialDetailTableData.value.some(
|
item => item.returned !== true && calcReturnQty(item) > 0
|
)
|
);
|
|
const loadDetailList = async () => {
|
if (!props.orderRow?.id) return;
|
materialDetailLoading.value = true;
|
materialDetailTableData.value = [];
|
try {
|
const res = await listMaterialPickingDetail(props.orderRow.id);
|
materialDetailTableData.value = (res.data || []).map(item => ({
|
...item,
|
actualQty:
|
item.actualQty ??
|
Number(item.pickQuantity || 0) + Number(item.feedingQty || 0),
|
returnQty: item.returnQty ?? 0,
|
}));
|
} finally {
|
materialDetailLoading.value = false;
|
}
|
};
|
|
watch(
|
() => dialogVisible.value,
|
visible => {
|
if (visible) {
|
loadDetailList();
|
}
|
}
|
);
|
|
const handleClose = () => {
|
materialDetailTableData.value = [];
|
};
|
|
const handleActualQtyChange = (row, val) => {
|
row.returnQty = calcReturnQty(row);
|
};
|
|
const handleViewSupplementRecord = async row => {
|
if (!row?.id) return;
|
supplementRecordDialogVisible.value = true;
|
supplementRecordLoading.value = true;
|
supplementRecordTableData.value = [];
|
try {
|
const res = await listMaterialSupplementRecord({
|
pickId: row.id,
|
productionOrderId: props.orderRow.id,
|
});
|
supplementRecordTableData.value = res.data || [];
|
} finally {
|
supplementRecordLoading.value = false;
|
}
|
};
|
|
const buildReturnSummary = () => {
|
const map = new Map();
|
materialDetailTableData.value.forEach(item => {
|
const returnQty = calcReturnQty(item);
|
if (returnQty <= 0) return;
|
const key = `${item.productModelId || ""}_${item.productName || ""}_${
|
item.model || ""
|
}_${item.unit || ""}`;
|
const old = map.get(key) || {
|
summaryKey: key,
|
materialName: item.productName || "",
|
materialModel: item.model || "",
|
unit: item.unit || "",
|
returnQtyTotal: 0,
|
};
|
old.returnQtyTotal += returnQty;
|
map.set(key, old);
|
});
|
return Array.from(map.values());
|
};
|
|
const openReturnSummaryDialog = async () => {
|
if (!canOpenReturnSummary.value) {
|
ElMessage.warning("退料数量=领用数量+补料数量-实际数量,且需大于0");
|
return;
|
}
|
returnSummaryList.value = buildReturnSummary();
|
returnSummaryDialogVisible.value = true;
|
};
|
|
const handleReturnConfirm = async () => {
|
if (!props.orderRow?.id) return;
|
materialReturnConfirming.value = true;
|
try {
|
await updateMaterialPickingLedger({
|
productionOrderId: props.orderRow.id,
|
productionOrderPickDto: materialDetailTableData.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,
|
feedingQty: item.feedingQty,
|
returnQty: item.returnQty,
|
actualQty: item.actualQty,
|
feedingReason: item.feedingReason,
|
returned: true,
|
})),
|
});
|
returnSummaryDialogVisible.value = false;
|
dialogVisible.value = false;
|
emit("confirmed");
|
} finally {
|
materialReturnConfirming.value = false;
|
}
|
};
|
</script>
|
|
<style scoped lang="scss"></style>
|