From dacc95761cf7090c628fc37a5d4f8bb825ccbbb0 Mon Sep 17 00:00:00 2001
From: yyb <995253665@qq.com>
Date: 星期六, 16 五月 2026 15:41:45 +0800
Subject: [PATCH] 企业新闻和通知公告
---
src/views/productionManagement/productionOrder/components/MaterialDetailDialog.vue | 462 ++++++++++++++++++++++++++++++---------------------------
1 files changed, 241 insertions(+), 221 deletions(-)
diff --git a/src/views/productionManagement/productionOrder/components/MaterialDetailDialog.vue b/src/views/productionManagement/productionOrder/components/MaterialDetailDialog.vue
index f93199a..370815e 100644
--- a/src/views/productionManagement/productionOrder/components/MaterialDetailDialog.vue
+++ b/src/views/productionManagement/productionOrder/components/MaterialDetailDialog.vue
@@ -1,43 +1,97 @@
<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="processName" min-width="180" />
- <el-table-column label="鍘熸枡鍚嶇О" prop="materialName" min-width="160" />
- <el-table-column label="鍘熸枡鍨嬪彿" prop="materialModel" min-width="180" />
- <el-table-column label="闇�姹傛暟閲�" prop="requiredQty" min-width="110" />
- <el-table-column label="璁¢噺鍗曚綅" prop="unit" width="100" />
- <el-table-column label="棰嗙敤鏁伴噺" prop="pickQty" min-width="110" />
- <el-table-column label="琛ユ枡鏁伴噺" min-width="120">
+ <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.supplementQty ?? 0 }}
+ <el-button type="primary"
+ link
+ @click="handleViewSupplementRecord(row)">
+ {{ row.feedingQty ?? 0 }}
</el-button>
</template>
</el-table-column>
- <el-table-column label="閫�鏂欐暟閲�" prop="returnQty" min-width="110" />
- <el-table-column label="瀹為檯鏁伴噺" prop="actualQty" min-width="110" />
+ <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
- type="warning"
- :loading="materialReturnConfirming"
- :disabled="!canOpenReturnSummary"
- @click="openReturnSummaryDialog"
- >
+ <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="supplementQty" min-width="120" />
- <el-table-column label="琛ユ枡鏃堕棿" prop="supplementTime" min-width="180" />
- <el-table-column label="澶囨敞" prop="remark" min-width="200" />
+ <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">
@@ -45,41 +99,30 @@
</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-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>
-
- <el-card class="approver-card" shadow="never">
- <template #header>
- <div class="card-header-wrapper">
- <span class="card-title">瀹℃壒浜洪�夋嫨</span>
- <el-button type="primary" size="small" @click="addApproverNode">鏂板鑺傜偣</el-button>
- </div>
- </template>
- <div class="approver-nodes-container">
- <div v-for="(node, index) in approverNodes" :key="node.id" class="approver-node-item">
- <div class="approver-node-label">
- <span class="node-step">{{ index + 1 }}</span>
- <span class="node-text">瀹℃壒浜�</span>
- </div>
- <el-select v-model="node.userId" placeholder="閫夋嫨浜哄憳" class="approver-select" clearable>
- <el-option v-for="user in userList" :key="user.userId" :label="user.nickName" :value="user.userId" />
- </el-select>
- <el-button v-if="approverNodes.length > 1" type="danger" size="small" @click="removeApproverNode(index)">
- 鍒犻櫎
- </el-button>
- </div>
- </div>
- </el-card>
-
<template #footer>
<span class="dialog-footer">
- <el-button type="primary" :loading="materialReturnConfirming" @click="handleReturnConfirm">纭鎻愪氦</el-button>
+ <el-button type="primary"
+ :loading="materialReturnConfirming"
+ @click="handleReturnConfirm">纭鎻愪氦</el-button>
<el-button @click="returnSummaryDialogVisible = false">鍙栨秷</el-button>
</span>
</template>
@@ -88,177 +131,154 @@
</template>
<script setup>
-import { computed, ref, watch } from "vue";
-import { ElMessage } from "element-plus";
-import { listMaterialPickingDetail, listMaterialSupplementRecord, confirmMaterialReturn } from "@/api/productionManagement/productionOrder.js";
-import { userListNoPageByTenantId } from "@/api/system/user.js";
+ 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 userList = ref([]);
-const approverNodes = ref([{ id: Date.now(), userId: undefined }]);
-const canOpenReturnSummary = computed(() =>
- materialDetailTableData.value.some(item => Number(item.returnQty || 0) > 0)
-);
-
-const loadDetailList = async () => {
- if (!props.orderRow?.id) return;
- materialDetailLoading.value = true;
- materialDetailTableData.value = [];
- try {
- const res = await listMaterialPickingDetail({ orderId: props.orderRow.id });
- materialDetailTableData.value = res.data || [];
- } finally {
- materialDetailLoading.value = false;
- }
-};
-
-watch(
- () => dialogVisible.value,
- visible => {
- if (visible) {
- loadDetailList();
- }
- }
-);
-
-const handleClose = () => {
- materialDetailTableData.value = [];
-};
-
-const handleViewSupplementRecord = async row => {
- if (!row?.id) return;
- supplementRecordDialogVisible.value = true;
- supplementRecordLoading.value = true;
- supplementRecordTableData.value = [];
- try {
- const res = await listMaterialSupplementRecord({ materialDetailId: row.id });
- supplementRecordTableData.value = res.data || [];
- } finally {
- supplementRecordLoading.value = false;
- }
-};
-
-const buildReturnSummary = () => {
- const map = new Map();
- materialDetailTableData.value.forEach(item => {
- const key = `${item.materialModelId || ""}_${item.materialName || ""}_${item.materialModel || ""}_${item.unit || ""}`;
- const old = map.get(key) || {
- summaryKey: key,
- materialName: item.materialName || "",
- materialModel: item.materialModel || "",
- unit: item.unit || "",
- returnQtyTotal: 0,
- };
- old.returnQtyTotal += Number(item.returnQty || 0);
- map.set(key, old);
+ const props = defineProps({
+ modelValue: { type: Boolean, default: false },
+ orderRow: { type: Object, default: null },
});
- return Array.from(map.values());
-};
+ const emit = defineEmits(["update:modelValue", "confirmed"]);
-const loadUserList = async () => {
- if (userList.value.length > 0) return;
- const res = await userListNoPageByTenantId();
- userList.value = res.data || [];
-};
+ const dialogVisible = computed({
+ get: () => props.modelValue,
+ set: val => emit("update:modelValue", val),
+ });
-const openReturnSummaryDialog = async () => {
- if (!canOpenReturnSummary.value) {
- ElMessage.warning("閫�鏂欐暟閲忓ぇ浜�0鏃舵墠鑳介��鏂欑‘璁�");
- return;
- }
- returnSummaryList.value = buildReturnSummary();
- approverNodes.value = [{ id: Date.now(), userId: undefined }];
- await loadUserList();
- returnSummaryDialogVisible.value = true;
-};
+ 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 addApproverNode = () => {
- approverNodes.value.push({ id: Date.now() + Math.random(), userId: undefined });
-};
+ 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;
+ }
+ };
-const removeApproverNode = index => {
- approverNodes.value.splice(index, 1);
-};
+ watch(
+ () => dialogVisible.value,
+ visible => {
+ if (visible) {
+ loadDetailList();
+ }
+ }
+ );
-const handleReturnConfirm = async () => {
- if (!props.orderRow?.id) return;
- const approverList = approverNodes.value
- .filter(item => item.userId)
- .map((item, index) => ({ userId: item.userId, sort: index + 1 }));
- if (approverList.length === 0) {
- ElMessage.warning("璇疯嚦灏戦�夋嫨涓�浣嶅鎵逛汉");
- return;
- }
- materialReturnConfirming.value = true;
- try {
- await confirmMaterialReturn({
- orderId: props.orderRow.id,
- returnSummaryList: returnSummaryList.value,
- approverList,
+ 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);
});
- returnSummaryDialogVisible.value = false;
- dialogVisible.value = false;
- emit("confirmed");
- } finally {
- materialReturnConfirming.value = false;
- }
-};
+ 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">
-.approver-card {
- margin-top: 12px;
-}
-.card-header-wrapper {
- display: flex;
- align-items: center;
- justify-content: space-between;
-}
-.approver-nodes-container {
- display: flex;
- flex-direction: column;
- gap: 8px;
-}
-.approver-node-item {
- display: flex;
- gap: 8px;
- align-items: center;
-}
-.approver-node-label {
- display: flex;
- gap: 4px;
- min-width: 88px;
- align-items: center;
-}
-.node-step {
- width: 20px;
- height: 20px;
- line-height: 20px;
- text-align: center;
- border-radius: 50%;
- background: #409eff;
- color: #fff;
- font-size: 12px;
-}
-.approver-select {
- flex: 1;
-}
-</style>
+<style scoped lang="scss"></style>
--
Gitblit v1.9.3