From 6d4e2e28287d66e749b8f7fc51a478640f0f8291 Mon Sep 17 00:00:00 2001
From: spring <2396852758@qq.com>
Date: 星期四, 16 四月 2026 14:34:13 +0800
Subject: [PATCH] fix: 是否入库、是否报工字段修改

---
 src/views/productionManagement/productionOrder/index.vue |  459 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++-
 1 files changed, 451 insertions(+), 8 deletions(-)

diff --git a/src/views/productionManagement/productionOrder/index.vue b/src/views/productionManagement/productionOrder/index.vue
index 3af5008..c66a0ec 100644
--- a/src/views/productionManagement/productionOrder/index.vue
+++ b/src/views/productionManagement/productionOrder/index.vue
@@ -42,6 +42,7 @@
       </el-form>
       <div>
         <el-button type="primary" @click="isShowNewModal = true">鏂板</el-button>
+        <el-button type="danger" @click="handleDelete">鍒犻櫎</el-button>
         <el-button @click="handleOut">瀵煎嚭</el-button>
       </div>
     </div>
@@ -52,6 +53,8 @@
                 :page="page"
                 :tableLoading="tableLoading"
                 :row-class-name="tableRowClassName"
+                :isSelection="true"
+                @selection-change="handleSelectionChange"
                 @pagination="pagination">
         <template #completionStatus="{ row }">
           <el-progress
@@ -80,10 +83,166 @@
       </el-form>
       <template #footer>
         <span class="dialog-footer">
-          <el-button @click="bindRouteDialogVisible = false">鍙� 娑�</el-button>
           <el-button type="primary"
                      :loading="bindRouteSaving"
                      @click="handleBindRouteConfirm">纭� 璁�</el-button>
+          <el-button @click="bindRouteDialogVisible = false">鍙� 娑�</el-button>
+        </span>
+      </template>
+    </el-dialog>
+
+    <el-dialog
+      v-model="materialDialogVisible"
+      title="棰嗘枡鍙拌处"
+      width="1200px"
+      @close="handleMaterialDialogClose"
+    >
+      <div class="material-toolbar">
+        <el-button type="primary" @click="handleAddMaterialRow">鏂板</el-button>
+      </div>
+      <el-table
+        v-loading="materialTableLoading"
+        :data="materialTableData"
+        border
+        row-key="tempId"
+      >
+        <el-table-column label="宸ュ簭鍚嶇О" min-width="180">
+          <template #default="{ row }">
+            <el-select
+              v-model="row.processId"
+              placeholder="璇烽�夋嫨宸ュ簭"
+              clearable
+              filterable
+              style="width: 100%;"
+              @change="val => handleProcessChange(row, val)"
+            >
+              <el-option
+                v-for="item in processOptions"
+                :key="item.id"
+                :label="item.name"
+                :value="item.id"
+              />
+            </el-select>
+          </template>
+        </el-table-column>
+        <el-table-column label="鍘熸枡鍚嶇О" min-width="160">
+          <template #default="{ row }">
+            <el-button type="primary" link @click="openMaterialProductSelect(row)">
+              {{ row.materialName || "閫夋嫨鍘熸枡" }}
+            </el-button>
+          </template>
+        </el-table-column>
+        <el-table-column label="鍘熸枡鍨嬪彿" min-width="180">
+          <template #default="{ row }">
+            {{ row.materialModel || "-" }}
+          </template>
+        </el-table-column>
+        <el-table-column label="闇�姹傛暟閲�" min-width="120">
+          <template #default="{ row }">
+            <el-input-number
+              v-model="row.requiredQty"
+              :min="0"
+              :precision="3"
+              :step="1"
+              controls-position="right"
+              style="width: 100%;"
+              @change="val => handleRequiredQtyChange(row, val)"
+            />
+          </template>
+        </el-table-column>
+        <el-table-column label="璁¢噺鍗曚綅" width="120">
+          <template #default="{ row }">
+            {{ row.unit || "-" }}
+          </template>
+        </el-table-column>
+        <el-table-column label="棰嗙敤鏁伴噺" min-width="120">
+          <template #default="{ row }">
+            <el-input-number
+              v-model="row.pickQty"
+              :min="0"
+              :precision="3"
+              :step="1"
+              controls-position="right"
+              style="width: 100%;"
+            />
+          </template>
+        </el-table-column>
+        <el-table-column label="鎿嶄綔" width="90" fixed="right">
+          <template #default="{ $index }">
+            <el-button type="danger" link @click="handleDeleteMaterialRow($index)">鍒犻櫎</el-button>
+          </template>
+        </el-table-column>
+      </el-table>
+      <template #footer>
+        <span class="dialog-footer">
+          <el-button type="primary" :loading="materialSaving" @click="handleMaterialSave">淇濆瓨</el-button>
+          <el-button @click="materialDialogVisible = false">鍙栨秷</el-button>
+        </span>
+      </template>
+    </el-dialog>
+
+    <ProductSelectDialog
+      v-model="materialProductDialogVisible"
+      @confirm="handleMaterialProductConfirm"
+      single
+    />
+
+    <el-dialog
+      v-model="materialDetailDialogVisible"
+      title="棰嗘枡璇︽儏"
+      width="1400px"
+      @close="handleMaterialDetailDialogClose"
+    >
+      <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">
+          <template #default="{ row }">
+            <el-button type="primary" link @click="handleViewSupplementRecord(row)">
+              {{ row.supplementQty ?? 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>
+      <template #footer>
+        <span class="dialog-footer">
+          <el-button type="warning" :loading="materialReturnConfirming" @click="handleReturnConfirm">
+            閫�鏂欑‘璁�
+          </el-button>
+          <el-button @click="materialDetailDialogVisible = 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-table>
+      <template #footer>
+        <span class="dialog-footer">
+          <el-button @click="supplementRecordDialogVisible = false">鍏抽棴</el-button>
         </span>
       </template>
     </el-dialog>
@@ -95,17 +254,25 @@
 </template>
 
 <script setup>
-  import { onMounted, ref } from "vue";
+  import { computed, defineAsyncComponent, getCurrentInstance, onMounted, reactive, ref, toRefs } from "vue";
   import { ElMessageBox } from "element-plus";
   import dayjs from "dayjs";
   import { useRouter } from "vue-router";
+  import ProductSelectDialog from "@/views/basicData/product/ProductSelectDialog.vue";
   import {
     productOrderListPage,
     listProcessRoute,
     bindingRoute,
-    listProcessBom,
+    listProcessBom, delProductOrder,
+    listMaterialPickingLedger,
+    saveMaterialPickingLedger,
+    listMaterialPickingDetail,
+    listMaterialSupplementRecord,
+    confirmMaterialReturn,
   } from "@/api/productionManagement/productionOrder.js";
   import { listMain as getOrderProcessRouteMain } from "@/api/productionManagement/productProcessRoute.js";
+  import { processList } from "@/api/productionManagement/productionProcess.js";
+  import PIMTable from "@/components/PIMTable/PIMTable.vue";
   const NewProductOrder = defineAsyncComponent(() => import("@/views/productionManagement/productionOrder/New.vue"));
 
   const { proxy } = getCurrentInstance();
@@ -182,7 +349,7 @@
       label: "鎿嶄綔",
       align: "center",
       fixed: "right",
-      width: 200,
+      width: 340,
       operation: [
         {
           name: "宸ヨ壓璺嚎",
@@ -206,6 +373,20 @@
             showProductStructure(row);
           },
         },
+        {
+          name: "棰嗘枡",
+          type: "text",
+          clickFun: row => {
+            openMaterialDialog(row);
+          },
+        },
+        {
+          name: "棰嗘枡璇︽儏",
+          type: "text",
+          clickFun: row => {
+            openMaterialDetailDialog(row);
+          },
+        },
       ],
     },
   ]);
@@ -216,6 +397,7 @@
     size: 100,
     total: 0,
   });
+  const selectedRows = ref([]);
 
   const data = reactive({
     searchForm: {
@@ -247,6 +429,7 @@
 
   // 娣诲姞琛ㄨ绫诲悕鏂规硶
   const tableRowClassName = ({ row }) => {
+    if (!row.deliveryDate) return '';
     if (row.isFh) return '';
 
     const diff = row.deliveryDaysDiff;
@@ -269,6 +452,36 @@
   const bindForm = reactive({
     orderId: null,
     routeId: null,
+  });
+  const materialDialogVisible = ref(false);
+  const materialProductDialogVisible = ref(false);
+  const materialTableLoading = ref(false);
+  const materialSaving = ref(false);
+  const materialTableData = ref([]);
+  const processOptions = ref([]);
+  const currentMaterialOrder = ref(null);
+  const currentMaterialSelectRowIndex = ref(-1);
+  const materialDetailDialogVisible = ref(false);
+  const materialDetailLoading = ref(false);
+  const materialDetailTableData = ref([]);
+  const materialReturnConfirming = ref(false);
+  const currentMaterialDetailOrder = ref(null);
+  const supplementRecordDialogVisible = ref(false);
+  const supplementRecordLoading = ref(false);
+  const supplementRecordTableData = ref([]);
+  let materialTempId = 0;
+
+  const createMaterialRow = (row = {}) => ({
+    tempId: row.id || `temp_${++materialTempId}`,
+    id: row.id,
+    processId: row.processId,
+    processName: row.processName || "",
+    materialModelId: row.materialModelId,
+    materialName: row.materialName || "",
+    materialModel: row.materialModel || "",
+    requiredQty: Number(row.requiredQty ?? 0),
+    unit: row.unit || "",
+    pickQty: Number(row.pickQty ?? row.requiredQty ?? 0),
   });
 
   const openBindRouteDialog = async row => {
@@ -312,6 +525,201 @@
       proxy.$modal.msgError("缁戝畾宸ヨ壓璺嚎澶辫触");
     } finally {
       bindRouteSaving.value = false;
+    }
+  };
+
+  const getProcessOptions = async () => {
+    if (processOptions.value.length > 0) return;
+    try {
+      const res = await processList({});
+      processOptions.value = res.data || [];
+    } catch (e) {
+      console.error("鑾峰彇宸ュ簭鍒楄〃澶辫触锛�", e);
+      proxy.$modal.msgError("鑾峰彇宸ュ簭鍒楄〃澶辫触");
+    }
+  };
+
+  const openMaterialDialog = async row => {
+    currentMaterialOrder.value = row;
+    materialDialogVisible.value = true;
+    materialTableLoading.value = true;
+    materialTableData.value = [];
+    await getProcessOptions();
+    try {
+      const res = await listMaterialPickingLedger({ orderId: row.id });
+      const list = res.data || [];
+      materialTableData.value = list.map(item => createMaterialRow(item));
+    } catch (e) {
+      console.error("鑾峰彇棰嗘枡鍙拌处澶辫触锛�", e);
+      proxy.$modal.msgError("鑾峰彇棰嗘枡鍙拌处澶辫触");
+    } finally {
+      materialTableLoading.value = false;
+    }
+  };
+
+  const handleMaterialDialogClose = () => {
+    materialTableData.value = [];
+    currentMaterialOrder.value = null;
+    currentMaterialSelectRowIndex.value = -1;
+  };
+
+  const handleAddMaterialRow = () => {
+    materialTableData.value.push(createMaterialRow());
+  };
+
+  const handleDeleteMaterialRow = index => {
+    materialTableData.value.splice(index, 1);
+  };
+
+  const handleProcessChange = (row, processId) => {
+    const process = processOptions.value.find(item => item.id === processId);
+    row.processName = process?.name || "";
+  };
+
+  const handleRequiredQtyChange = (row, val) => {
+    const required = Number(val ?? 0);
+    row.requiredQty = required;
+    if (!row.pickQty || Number(row.pickQty) === 0) {
+      row.pickQty = required;
+    }
+  };
+
+  const openMaterialProductSelect = row => {
+    currentMaterialSelectRowIndex.value = materialTableData.value.findIndex(item => item.tempId === row.tempId);
+    materialProductDialogVisible.value = true;
+  };
+
+  const handleMaterialProductConfirm = products => {
+    if (!products || products.length === 0) return;
+    const index = currentMaterialSelectRowIndex.value;
+    if (index < 0 || !materialTableData.value[index]) return;
+    const product = products[0];
+    const row = materialTableData.value[index];
+    row.materialModelId = product.id;
+    row.materialName = product.productName || "";
+    row.materialModel = product.model || "";
+    row.unit = product.unit || "";
+    currentMaterialSelectRowIndex.value = -1;
+    materialProductDialogVisible.value = false;
+  };
+
+  const validateMaterialRows = () => {
+    if (materialTableData.value.length === 0) {
+      proxy.$modal.msgWarning("璇疯嚦灏戞柊澧炰竴鏉¢鏂欒褰�");
+      return false;
+    }
+    const invalidRow = materialTableData.value.find(
+      item =>
+        !item.processId ||
+        !item.materialModelId ||
+        item.requiredQty === null ||
+        item.requiredQty === undefined ||
+        item.pickQty === null ||
+        item.pickQty === undefined
+    );
+    if (invalidRow) {
+      proxy.$modal.msgWarning("璇峰畬鍠勯鏂欏彴璐﹀繀濉瓧娈�");
+      return false;
+    }
+    return true;
+  };
+
+  const handleMaterialSave = async () => {
+    if (!currentMaterialOrder.value?.id) {
+      proxy.$modal.msgWarning("鏈幏鍙栧埌褰撳墠鐢熶骇璁㈠崟");
+      return;
+    }
+    if (!validateMaterialRows()) return;
+    materialSaving.value = true;
+    try {
+      await saveMaterialPickingLedger({
+        orderId: currentMaterialOrder.value.id,
+        items: materialTableData.value.map(item => ({
+          id: item.id,
+          processId: item.processId,
+          processName: item.processName,
+          materialModelId: item.materialModelId,
+          materialName: item.materialName,
+          materialModel: item.materialModel,
+          requiredQty: item.requiredQty,
+          unit: item.unit,
+          pickQty: item.pickQty,
+        })),
+      });
+      proxy.$modal.msgSuccess("淇濆瓨鎴愬姛");
+      materialDialogVisible.value = false;
+    } catch (e) {
+      console.error("淇濆瓨棰嗘枡鍙拌处澶辫触锛�", e);
+      proxy.$modal.msgError("淇濆瓨棰嗘枡鍙拌处澶辫触");
+    } finally {
+      materialSaving.value = false;
+    }
+  };
+
+  const openMaterialDetailDialog = async row => {
+    currentMaterialDetailOrder.value = row;
+    materialDetailDialogVisible.value = true;
+    materialDetailLoading.value = true;
+    materialDetailTableData.value = [];
+    try {
+      const res = await listMaterialPickingDetail({ orderId: row.id });
+      materialDetailTableData.value = res.data || [];
+    } catch (e) {
+      console.error("鑾峰彇棰嗘枡璇︽儏澶辫触锛�", e);
+      proxy.$modal.msgError("鑾峰彇棰嗘枡璇︽儏澶辫触");
+    } finally {
+      materialDetailLoading.value = false;
+    }
+  };
+
+  const handleMaterialDetailDialogClose = () => {
+    materialDetailTableData.value = [];
+    currentMaterialDetailOrder.value = null;
+  };
+
+  const handleViewSupplementRecord = async row => {
+    if (!row?.id) {
+      proxy.$modal.msgWarning("缂哄皯棰嗘枡鏄庣粏ID锛屾棤娉曟煡鐪嬭ˉ鏂欒褰�");
+      return;
+    }
+    supplementRecordDialogVisible.value = true;
+    supplementRecordLoading.value = true;
+    supplementRecordTableData.value = [];
+    try {
+      const res = await listMaterialSupplementRecord({ materialDetailId: row.id });
+      supplementRecordTableData.value = res.data || [];
+    } catch (e) {
+      console.error("鑾峰彇琛ユ枡璁板綍澶辫触锛�", e);
+      proxy.$modal.msgError("鑾峰彇琛ユ枡璁板綍澶辫触");
+    } finally {
+      supplementRecordLoading.value = false;
+    }
+  };
+
+  const handleReturnConfirm = async () => {
+    if (!currentMaterialDetailOrder.value?.id) {
+      proxy.$modal.msgWarning("鏈幏鍙栧埌褰撳墠鐢熶骇璁㈠崟");
+      return;
+    }
+    try {
+      await ElMessageBox.confirm("纭鎵ц閫�鏂欑‘璁わ紵", "鎻愮ず", {
+        confirmButtonText: "纭",
+        cancelButtonText: "鍙栨秷",
+        type: "warning",
+      });
+    } catch (e) {
+      return;
+    }
+    materialReturnConfirming.value = true;
+    try {
+      await confirmMaterialReturn({ orderId: currentMaterialDetailOrder.value.id });
+      proxy.$modal.msgSuccess("閫�鏂欑‘璁ゆ垚鍔�");
+      openMaterialDetailDialog(currentMaterialDetailOrder.value);
+    } catch (e) {
+      console.error("閫�鏂欑‘璁ゅけ璐ワ細", e);
+      proxy.$modal.msgError("閫�鏂欑‘璁ゅけ璐�");
+    } finally {
+      materialReturnConfirming.value = false;
     }
   };
 
@@ -394,6 +802,33 @@
     });
   };
 
+  // 琛ㄦ牸閫夋嫨鏁版嵁
+  const handleSelectionChange = (selection) => {
+    selectedRows.value = selection;
+  };
+
+  const handleDelete = () => {
+    let ids = [];
+    if (selectedRows.value.length > 0) {
+      ids = selectedRows.value.map((item) => item.id);
+    } else {
+      proxy.$modal.msgWarning("璇烽�夋嫨鏁版嵁");
+      return;
+    }
+    ElMessageBox.confirm("閫変腑鐨勫唴瀹瑰皢琚垹闄わ紝鏄惁纭鍒犻櫎锛�", "瀵煎嚭", {
+      confirmButtonText: "纭",
+      cancelButtonText: "鍙栨秷",
+      type: "warning",
+    }).then(() => {
+      delProductOrder(ids).then((res) => {
+        proxy.$modal.msgSuccess("鍒犻櫎鎴愬姛");
+        getList();
+      });
+    }).catch(() => {
+      proxy.$modal.msg("宸插彇娑�");
+    });
+  };
+
   // 瀵煎嚭
   const handleOut = () => {
     ElMessageBox.confirm("閫変腑鐨勫唴瀹瑰皢琚鍑猴紝鏄惁纭瀵煎嚭锛�", "瀵煎嚭", {
@@ -421,19 +856,27 @@
   align-items: start;
 }
 
-::v-deep .yellow {
+:deep(.yellow) {
   background-color: #FAF0DE;
 }
 
-::v-deep .pink {
+:deep(.pink) {
   background-color: #FAE1DE;
 }
 
-::v-deep .red {
+:deep(.red) {
   background-color: #f80202;
 }
 
-::v-deep .purple{
+:deep(.purple){
   background-color: #F4DEFA;
 }
+.table_list {
+	margin-top: unset;
+}
+
+.material-toolbar {
+  margin-bottom: 12px;
+  text-align: right;
+}
 </style>

--
Gitblit v1.9.3