From 80fea9ca648dcebc3b44fa068c927fa67dafb7fb Mon Sep 17 00:00:00 2001
From: 张诺 <zhang_12370@163.com>
Date: 星期三, 29 四月 2026 10:27:41 +0800
Subject: [PATCH] fix(workOrder): 修正工单报告数量计算逻辑

---
 src/views/productionManagement/workOrder/index.vue |  319 +++++++++++++++++++++++++++++++++--------------------
 1 files changed, 198 insertions(+), 121 deletions(-)

diff --git a/src/views/productionManagement/workOrder/index.vue b/src/views/productionManagement/workOrder/index.vue
index 18423af..7fcdab2 100644
--- a/src/views/productionManagement/workOrder/index.vue
+++ b/src/views/productionManagement/workOrder/index.vue
@@ -234,7 +234,7 @@
                   placeholder="璇烽�夋嫨鐝粍鎴愬憳"
               >
                 <el-option
-                    v-for="user in userTeamOptions"
+                    v-for="user in reportForm.userIdsList"
                     :key="user.userId"
                     :label="user.nickName"
                     :value="{ userId: user.userId, userName: user.nickName }"
@@ -243,25 +243,25 @@
             </el-form-item>
           </el-col>
 
-          <el-col :span="12">
-            <el-form-item label="鏈哄彴" prop="deviceId">
-              <el-select
-                  v-model="reportForm.deviceId"
-                  placeholder="璇烽�夋嫨鏈哄彴"
-                  filterable
-                  clearable
-                  @change="(val) => handleDeviceChange(val)"
-                  :disabled="isDetail"
-              >
-                <el-option
-                    v-for="item in deviceOptions"
-                    :key="item.id"
-                    :label="item.deviceName"
-                    :value="item.id"
-                />
-              </el-select>
-            </el-form-item>
-          </el-col>
+<!--          <el-col :span="12">-->
+<!--            <el-form-item label="鏈哄彴" prop="deviceId">-->
+<!--              <el-select-->
+<!--                  v-model="reportForm.deviceId"-->
+<!--                  placeholder="璇烽�夋嫨鏈哄彴"-->
+<!--                  filterable-->
+<!--                  clearable-->
+<!--                  @change="(val) => handleDeviceChange(val)"-->
+<!--                  :disabled="isDetail"-->
+<!--              >-->
+<!--                <el-option-->
+<!--                    v-for="item in deviceOptions"-->
+<!--                    :key="item.id"-->
+<!--                    :label="item.deviceName"-->
+<!--                    :value="item.id"-->
+<!--                />-->
+<!--              </el-select>-->
+<!--            </el-form-item>-->
+<!--          </el-col>-->
 
           <el-col :span="12">
             <el-form-item label="瀹℃牳浜�" prop="auditUserId">
@@ -326,21 +326,19 @@
       </template>
     </el-dialog>
     <el-dialog v-model="scheduleDialogVisible"
-               :title="`鐢熶骇鎺掍骇(宸ュ崟缂栧彿:${currentReportRowData?.workOrderNo || '-'})`"
+               :title="scheduleDialogTitle"
                width="1000px"
                :close-on-click-modal="false">
       <div class="schedule-panel">
-        <el-row style="margin-bottom: 12px;">
+        <el-row v-if="!isScheduleHistoryMode" style="margin-bottom: 12px;">
           <el-col>
             <el-button type="primary" plain :disabled="scheduleLoading || scheduleSaving" @click="addScheduleRow">
               鏂板涓�琛�
             </el-button>
           </el-col>
         </el-row>
-
         <el-table :data="scheduleRows" border style="width: 100%" v-loading="scheduleLoading">
-          <el-table-column type="index" label="搴忓彿" width="70" align="center" />
-
+          <el-table-column type="index" label="搴忓彿" width="70" align="center" :index="indexMethod" />
           <el-table-column label="鏈涓婃満鏈哄彴" min-width="220">
             <template #default="{ row }">
               <el-select
@@ -349,7 +347,7 @@
                   filterable
                   clearable
                   style="width: 100%"
-                  :disabled="scheduleSaving"
+                  :disabled="scheduleSaving || isScheduleHistoryMode"
                   @change="val => handleScheduleDeviceChange(val, row)"
               >
                 <el-option
@@ -364,7 +362,18 @@
 
           <el-table-column label="鏈涓婃満浜�" min-width="220">
             <template #default="{ row }">
+              <div v-if="isScheduleHistoryMode" class="schedule-user-tags">
+                <el-tag
+                    v-for="(userId, index) in row.userIds"
+                    :key="`${userId}-${index}`"
+                    type="primary"
+                >
+                  {{ resolveScheduleUserName(userId) }}
+                </el-tag>
+                <span v-if="!row.userIds?.length">-</span>
+              </div>
               <el-select
+                  v-else
                   v-model="row.userIds"
                   placeholder="璇烽�夋嫨涓婃満浜�"
                   filterable
@@ -394,12 +403,12 @@
                   format="YYYY-MM-DD HH:mm:ss"
                   placeholder="璇烽�夋嫨涓婃満鏃堕棿"
                   style="width: 100%"
-                  :disabled="scheduleSaving"
+                  :disabled="scheduleSaving || isScheduleHistoryMode"
               />
             </template>
           </el-table-column>
 
-          <el-table-column label="鎿嶄綔" width="110" align="center">
+          <el-table-column v-if="!isScheduleHistoryMode" label="鎿嶄綔" width="110" align="center">
             <template #default="{ row }">
               <el-button
                   link
@@ -415,7 +424,7 @@
         </el-table>
 
         <Pagination
-            v-show="schedulePage.total > 0"
+            v-show="isScheduleHistoryMode && schedulePage.total > 0"
             style="margin-top: 12px"
             :total="schedulePage.total"
             :page="schedulePage.current"
@@ -426,8 +435,13 @@
 
       <template #footer>
         <span class="dialog-footer">
-          <el-button type="primary" :loading="scheduleSaving" @click="handleSaveSchedule">淇濆瓨鎺掍骇</el-button>
-          <el-button :disabled="scheduleSaving" @click="scheduleDialogVisible = false">鍙栨秷</el-button>
+          <template v-if="isScheduleHistoryMode">
+            <el-button @click="scheduleDialogVisible = false">鍏抽棴</el-button>
+          </template>
+          <template v-else>
+            <el-button type="primary" :loading="scheduleSaving" @click="handleSaveSchedule">淇濆瓨鎺掍骇</el-button>
+            <el-button :disabled="scheduleSaving" @click="scheduleDialogVisible = false">鍙栨秷</el-button>
+          </template>
         </span>
       </template>
     </el-dialog>
@@ -441,6 +455,7 @@
 import {ElMessageBox, ElMessage} from "element-plus";
 import Pagination from "@/components/PIMTable/Pagination.vue";
 import dayjs from "dayjs";
+import { processList } from '@/api/productionManagement/productionProcess.js'
 import {
   productWorkOrderPage,
   updateProductWorkOrder,
@@ -500,50 +515,15 @@
   return [val];
 };
 
-const isCurrentUserReportWorker = (row) => {
+const isCurrentUserInUserIds = (row) => {
   const uid = String(currentUserId.value || "");
   if (!uid) return false;
-  if (!row) return false;
 
-  const candidateIds = [
-    row.reportUserIds,
-    row.reportWorkerIds,
-    row.userIdList,
-    row.reportUserId,
-    row.userId,
-  ]
-      .flatMap((v) => normalizeArray(v))
-      .map((v) => String(v))
+  const ids = normalizeArray(row?.userIds)
+      .map(id => String(id))
       .filter(Boolean);
 
-  if (candidateIds.includes(uid)) return true;
-
-  const candidateNames = [
-    row.userNames,
-    row.reportUserNames,
-    row.reportWorkerNames,
-    row.userName,
-  ]
-      .flatMap((v) => normalizeArray(v))
-      .map((v) => String(v))
-      .filter(Boolean);
-
-  if (currentUserName.value && candidateNames.includes(currentUserName.value)) {
-    return true;
-  }
-
-  if (Array.isArray(row.reportWorkerList)) {
-    const list = row.reportWorkerList
-        .map((item) => String(item?.userId ?? item?.id ?? ""))
-        .filter(Boolean);
-    if (list.includes(uid)) return true;
-    const nameList = row.reportWorkerList
-        .map((item) => String(item?.userName ?? item?.nickName ?? ""))
-        .filter(Boolean);
-    if (currentUserName.value && nameList.includes(currentUserName.value)) return true;
-  }
-
-  return false;
+  return ids.includes(uid);
 };
 
 const canOperateByReportWorker = computed(() => {
@@ -659,17 +639,12 @@
     return;
   }
 
-  const first = scheduleRows.value[0] || {};
-  const deviceId = first.deviceId || currentReportRowData.value?.deviceId || "";
-  const userOptions = deviceId ? buildScheduleUserOptionsByDeviceId(deviceId) : [...baseScheduleUsers.value];
-  const defaultUserId = userOptions[0]?.userId ? String(userOptions[0].userId) : "";
-
   scheduleRows.value.push(
     createScheduleRow({
       id: "",
-      deviceId,
-      deviceName: first.deviceName || currentReportRowData.value?.deviceName || "",
-      userIds: defaultUserId ? [defaultUserId] : [],
+      deviceId:"",
+      deviceName:"",
+      userIds: [],
       startTime: dayjs().format("YYYY-MM-DD HH:mm:ss"),
     })
   );
@@ -681,7 +656,7 @@
   if (!workOrderRow?.id) {
     schedulePage.current = 1;
     schedulePage.total = 0;
-    scheduleRows.value = [createScheduleRow({})];
+    scheduleRows.value = [];
     return;
   }
 
@@ -707,13 +682,12 @@
       return;
     }
 
-    const rows = buildScheduleRowsFromRecords(records);
-
-    scheduleRows.value = rows.length > 0 ? rows : [createScheduleRow({})];
+    const rows = records.map(record => mapMachineRecordToScheduleRow(record));
+    scheduleRows.value = rows;
   } catch (error) {
     console.error("鑾峰彇鎺掍骇璁板綍澶辫触", error);
     schedulePage.total = 0;
-    scheduleRows.value = [createScheduleRow({})];
+    scheduleRows.value = [];
     ElMessage.error("鑾峰彇鎺掍骇璁板綍澶辫触");
   } finally {
     scheduleLoading.value = false;
@@ -721,12 +695,12 @@
 };
 
 const removeScheduleRow = async (row) => {
-  if (!row) return;
+  if (!row || isScheduleHistoryMode.value) return;
 
   if (!row.id) {
     scheduleRows.value = scheduleRows.value.filter((item) => item !== row);
     if (!scheduleRows.value.length) {
-      scheduleRows.value = [createScheduleRow({})];
+      addScheduleRow();
     }
     return;
   }
@@ -777,6 +751,7 @@
 };
 
 const handleSchedulePagination = ({page, limit}) => {
+  if (!isScheduleHistoryMode.value) return;
   schedulePage.current = page;
   schedulePage.size = limit;
   refreshScheduleRows();
@@ -851,6 +826,16 @@
   return payload;
 };
 
+const indexMethod = (index) => {
+  return (schedulePage.current - 1) * schedulePage.size + index + 1;
+};
+
+const scheduleDialogMode = ref("create");
+const isScheduleHistoryMode = computed(() => scheduleDialogMode.value === "history");
+const scheduleDialogTitle = computed(() =>
+  `${isScheduleHistoryMode.value ? "鎺掍骇璁板綍" : "鐢熶骇鎺掍骇"}(宸ュ崟缂栧彿:${currentReportRowData.value?.workOrderNo || "-"})`
+);
+
 const mapMachineRecordToScheduleRow = (record) => {
   const id = record?.id ?? "";
   const deviceId = record?.machineId ?? record?.deviceId ?? "";
@@ -896,11 +881,29 @@
   );
 };
 
+const resetCreateScheduleRows = () => {
+  schedulePage.current = 1;
+  schedulePage.total = 0;
+  scheduleRows.value = [];
+  addScheduleRow();
+};
+
 const openScheduleDialog = async (row) => {
+  scheduleDialogMode.value = "create";
+  currentReportRowData.value = row;
+  baseScheduleUsers.value = buildBaseScheduleUsersByRow(row);
+  userTemp.value = [...baseScheduleUsers.value];
+  scheduleDialogVisible.value = true;
+  resetCreateScheduleRows();
+};
+
+const openHistoryTimelineDialog = async (row) => {
+  scheduleDialogMode.value = "history";
   currentReportRowData.value = row;
   baseScheduleUsers.value = buildBaseScheduleUsersByRow(row);
   userTemp.value = [...baseScheduleUsers.value];
   schedulePage.current = 1;
+  schedulePage.total = 0;
   scheduleRows.value = [];
   scheduleDialogVisible.value = true;
 
@@ -908,6 +911,7 @@
 };
 
 const handleSaveSchedule = async () => {
+  if (isScheduleHistoryMode.value) return;
   if (scheduleSaving.value) return;
   if (!validateScheduleRows()) return;
 
@@ -932,7 +936,7 @@
     }
 
     proxy.$modal.msgSuccess("鎺掍骇宸蹭繚瀛�");
-    await refreshScheduleRows();
+    resetCreateScheduleRows();
     getList();
   } catch (error) {
     console.error("淇濆瓨鎺掍骇澶辫触", error);
@@ -1014,7 +1018,7 @@
   },
   {
     label: "鎿嶄綔",
-    width: "200",
+    width: "220",
     align: "center",
     dataType: "action",
     fixed: "right",
@@ -1042,13 +1046,32 @@
         clickFun: row => {
           showReportDialog(row);
         },
+        // 鐢ㄦ埛褰撳墠id
+        disabled: row => row.completeQuantity >= row.planQuantity ||
+            !isCurrentUserInUserIds(row)
       },
       {
         name: "鐢熶骇鎺掍骇",
         clickFun: row => {
+          if (!row.canSchedule) {
+            ElMessage.warning("褰撳墠鐢ㄦ埛涓嶅湪璇ュ伐搴忎汉鍛樹腑锛屼笉鑳界敓浜ф帓浜�");
+            return;
+          }
           openScheduleDialog(row);
         },
+        disabled: row => !row.canSchedule || row.completeQuantity >= row.planQuantity
       },
+      {
+        name: "鎺掍骇璁板綍",
+        clickFun: row => {
+          if (!row.canSchedule) {
+            ElMessage.warning("褰撳墠鐢ㄦ埛涓嶅湪璇ュ伐搴忎汉鍛樹腑锛屼笉鑳芥煡鐪嬫帓浜ц褰�");
+            return;
+          }
+          openHistoryTimelineDialog(row);
+        },
+        disabled: row => !row.canSchedule
+      }
       // {
       //   name:"瀹℃牳",
       //   color: "#f56c6c",
@@ -1209,6 +1232,12 @@
   if (isNaN(num)) {
     return;
   }
+  // 濡傛灉瓒呰繃寰呯敓浜ф暟閲�
+  if (num > reportForm.planQuantity) {
+    proxy.$modal.msgWarning("鏈鐢熶骇鏁伴噺涓嶈兘澶т簬寰呯敓浜ф暟閲�");
+    reportForm.quantity = reportForm.planQuantity;
+    return;
+  }
   // 濡傛灉灏忎簬1锛屾竻闄�
   if (num < 1) {
     reportForm.quantity = null;
@@ -1292,18 +1321,27 @@
   page.size = obj.limit;
   getList();
 };
-const getList = () => {
+const getList = async () => {
   tableLoading.value = true;
-  const params = {...searchForm.value, ...page};
-  productWorkOrderPage(params)
-      .then(res => {
-        tableLoading.value = false;
-        tableData.value = res.data.records;
-        page.total = res.data.total;
-      })
-      .catch(() => {
-        tableLoading.value = false;
-      });
+
+  try {
+    await ensureCurrentUser();
+    await processLists();
+
+    const params = { ...searchForm.value, ...page };
+    const res = await productWorkOrderPage(params);
+
+    const records = Array.isArray(res?.data?.records) ? res.data.records : [];
+
+    tableData.value = records.map(row => ({
+      ...row,
+      canSchedule: canScheduleByWorkOrderNo(row)
+    }));
+
+    page.total = res?.data?.total || 0;
+  } finally {
+    tableLoading.value = false;
+  }
 };
 
 // 涓嬭浇骞舵墦鍗板伐鍗曟祦杞崱锛堟枃浠舵祦锛�
@@ -1394,14 +1432,10 @@
 };
 
 const showReportDialog = row => {
-  // if (!isCurrentUserReportWorker(row)) {
-  //   ElMessage.warning("褰撳墠鐢ㄦ埛涓嶆槸璇ュ伐鍗曠殑鎶ュ伐浜猴紝鏃犳硶鎶ュ伐");
-  //   return;
-  // }
+
   currentReportRowData.value = row;
   reportForm.planQuantity = row.planQuantity - row.completeQuantity;
-  reportForm.quantity =
-      row.quantity !== undefined && row.quantity !== null ? row.quantity : null;
+  reportForm.quantity = row.planQuantity - row.completeQuantity;
   reportForm.productProcessRouteItemId = row.productProcessRouteItemId;
   reportForm.workOrderId = row.id;
   reportForm.reportWork = row.reportWork;
@@ -1411,6 +1445,20 @@
   reportForm.replenishQty = 0;
   reportForm.teamList = [];
   reportForm.scrapQty = 0;
+  reportForm.userIds = row.userIds || [];
+
+  const ids = (row.userIds || "")
+      .split(",")
+      .map(id => id.trim())
+      .filter(Boolean);
+
+  reportForm.userIdsList = userTeamOptions.value
+      .filter(item => ids.includes(String(item.userId)))
+      .map(item => ({
+        userId: item.userId,
+        nickName: item.nickName
+      }));
+
 
   nextTick(() => {
     reportFormRef.value?.clearValidate();
@@ -1483,20 +1531,6 @@
       return;
     }
 
-    if (!reportForm.startTime || !reportForm.endTime) {
-      ElMessageBox.alert("寮�濮嬫椂闂村拰缁撴潫鏃堕棿涓嶈兘涓虹┖", "鎻愮ず", {
-        confirmButtonText: "纭畾",
-      });
-      return;
-    }
-
-    if (dayjs(reportForm.startTime).isSame(dayjs(reportForm.endTime)) || dayjs(reportForm.startTime).isAfter(dayjs(reportForm.endTime))) {
-      ElMessageBox.alert("寮�濮嬫椂闂村繀椤诲皬浜庣粨鏉熸椂闂�", "鎻愮ず", {
-        confirmButtonText: "纭畾",
-      });
-      return;
-    }
-
     const submitData = {
       ...reportForm,
       quantity: quantity,
@@ -1557,9 +1591,44 @@
   }
 }
 
-onMounted(() => {
-  ensureCurrentUser();
-  getList();
+const processData = ref([]);
+
+// 鏌ヨ鎵�鏈夊伐搴�
+const processLists = async () => {
+  console.log(processData.value)
+  if (processData.value.length > 0) {
+    return processData.value;
+  }
+  const res = await processList();
+
+  processData.value = Array.isArray(res?.data) ? res.data : [];
+  return processData.value;
+};
+
+// 鍒ゆ柇褰撳墠鐢ㄦ埛鏄惁鑳芥帓浜�
+const canScheduleByWorkOrderNo = (row) => {
+  if (!row) return false;
+
+  const uid = String(currentUserId.value || "");
+  if (!uid) return false;
+
+  const currentProcess = processData.value.find(item =>
+      String(item.id) === String(row.processId)
+  );
+
+  if (!currentProcess) return false;
+
+  const ids = normalizeArray(currentProcess.userIds)
+      .map(id => String(id).trim())
+      .filter(Boolean);
+
+  return ids.includes(uid);
+};
+
+onMounted(async () => {
+  await ensureCurrentUser();
+  await processLists();
+  await getList();
   getUserList();
   getDeviceList();
 });
@@ -1627,6 +1696,14 @@
     justify-content: flex-start;
   }
 }
+
+.schedule-user-tags {
+  display: flex;
+  flex-wrap: wrap;
+  gap: 8px;
+  min-height: 32px;
+  align-items: center;
+}
 </style>
 
 <style lang="scss">

--
Gitblit v1.9.3