From 22229c67d87f0fae4c4bc90db106b8a1e2c49b53 Mon Sep 17 00:00:00 2001
From: 云 <2163098428@qq.com>
Date: 星期四, 20 八月 2026 15:50:11 +0800
Subject: [PATCH] feat(permission): 为多个模块添加管理员权限控制功能

---
 src/views/productionManagement/workOrder/index.vue |  170 +++++++++++++++++++++++++++++++++++++++++++++-----------
 1 files changed, 135 insertions(+), 35 deletions(-)

diff --git a/src/views/productionManagement/workOrder/index.vue b/src/views/productionManagement/workOrder/index.vue
index 18ece60..d8cc499 100644
--- a/src/views/productionManagement/workOrder/index.vue
+++ b/src/views/productionManagement/workOrder/index.vue
@@ -24,13 +24,7 @@
                 :tableData="tableData"
                 :page="page"
                 :tableLoading="tableLoading"
-                @pagination="pagination">
-        <template #completionStatus="{ row }">
-          <el-progress :percentage="toProgressPercentage(row?.completionStatus)"
-                       :color="progressColor(toProgressPercentage(row?.completionStatus))"
-                       :status="toProgressPercentage(row?.completionStatus) >= 100 ? 'success' : ''" />
-        </template>
-      </PIMTable>
+                @pagination="pagination" />
     </div>
     <el-dialog v-model="editDialogVisible"
                title="缂栬緫鏃堕棿"
@@ -233,6 +227,7 @@
             <el-form-item label="鐝粍淇℃伅"
                           prop="teamList">
               <el-select v-model="reportForm.teamList"
+                         ref="teamSelectRef"
                          multiple
                          filterable
                          allow-create
@@ -242,8 +237,8 @@
                          value-key="userName"
                          placeholder="璇烽�夋嫨鎴栬緭鍏ョ彮缁勬垚鍛�"
                          @change="handleTeamListChange">
-                <el-option v-for="user in reportForm.userIdsList"
-                           :key="user.userId"
+                <el-option v-for="user in teamSelectOptions"
+                           :key="user.userId || `custom-${user.nickName}`"
                            :label="user.nickName"
                            :value="{ userId: user.userId, userName: user.nickName }" />
               </el-select>
@@ -288,6 +283,19 @@
           <!--          </el-col>-->
         </el-row>
       </el-form>
+      <el-table :data="personList" border style="margin-top: 12px;">
+        <el-table-column label="鐢熶骇浜�" prop="userName" min-width="100" align="center" />
+        <el-table-column label="浜ч噺" min-width="120" align="center">
+          <template #default="scope">
+            <el-input-number v-model="scope.row.quantity" :min="0" :controls="false" placeholder="浜ч噺" style="width: 100%" />
+          </template>
+        </el-table-column>
+        <el-table-column label="鐢熶骇鏃堕暱(鍒嗛挓)" min-width="140" align="center">
+          <template #default="scope">
+            <el-input-number v-model="scope.row.workHour" :min="0" :controls="false" placeholder="鏃堕暱(鍒嗛挓)" style="width: 100%" />
+          </template>
+        </el-table-column>
+      </el-table>
       <template #footer>
         <span class="dialog-footer">
           <el-button type="primary"
@@ -489,6 +497,7 @@
     productWorkOrderPage,
     updateProductWorkOrder,
     addProductMain,
+    getProductWorkOrderById,
     downProductWorkOrder,
     addProductionMachineRecord,
     productionMachineRecordListPage,
@@ -499,12 +508,18 @@
   import { getCurrentInstance, reactive, toRefs } from "vue";
   import FilesDia from "./components/filesDia.vue";
   import { getDeviceLedger } from "@/api/equipmentManagement/ledger.js";
+  import useUserStore from "@/store/modules/user";
 
   const { proxy } = getCurrentInstance();
+  const userStore = useUserStore();
+  const isAdminUser = computed(() =>
+    ["admin", "鏅��2", "鏈�楂�1"].some(r => (userStore.roles || []).includes(r))
+  );
 
   const currentUserId = ref("");
   const deviceOptions = ref([]);
   const currentUserName = ref("");
+  const teamSelectRef = ref(null);
 
   const ensureCurrentUser = async () => {
     if (currentUserId.value) return;
@@ -567,9 +582,13 @@
     return ids.includes(uid);
   };
 
-  // 鍒ゆ柇褰撳墠鐢ㄦ埛鏄惁鍙互鎶ュ伐锛堝伐鍗曟姤宸ヤ汉 鎴� 宸ュ簭鎶ュ伐浜猴級
+  // 鍒ゆ柇褰撳墠鐢ㄦ埛鏄惁鍙互鎶ュ伐锛堝伐鍗曟姤宸ヤ汉 鎴� 宸ュ簭鎶ュ伐浜猴紝绠$悊鍛樹笉鍙楅檺锛�
   const canCurrentUserReport = row => {
-    return isCurrentUserInUserIds(row) || isCurrentUserInProcessUserIds(row);
+    return (
+      isAdminUser.value ||
+      isCurrentUserInUserIds(row) ||
+      isCurrentUserInProcessUserIds(row)
+    );
   };
 
   const canOperateByReportWorker = computed(() => {
@@ -1073,25 +1092,13 @@
       width: "140",
     },
     {
+      label: "鍔犳斁鏁�",
+      prop: "processRouteAddNum",
+      width: "100",
+    },
+    {
       label: "瀹屾垚鏁伴噺",
       prop: "completeQuantity",
-      width: "140",
-    },
-    {
-      label: "瀹屾垚杩涘害",
-      prop: "completionStatus",
-      dataType: "slot",
-      slot: "completionStatus",
-      width: "140",
-    },
-    {
-      label: "璁″垝寮�濮嬫椂闂�",
-      prop: "planStartTime",
-      width: "140",
-    },
-    {
-      label: "璁″垝缁撴潫鏃堕棿",
-      prop: "planEndTime",
       width: "140",
     },
     {
@@ -1134,11 +1141,10 @@
           clickFun: row => {
             showReportDialog(row);
           },
-          // 鐢ㄦ埛褰撳墠id鍦ㄥ伐鍗曟姤宸ヤ汉鎴栧伐搴忔姤宸ヤ汉涓�
+          // 鐢ㄦ埛褰撳墠id鍦ㄥ伐鍗曟姤宸ヤ汉鎴栧伐搴忔姤宸ヤ汉涓紝涓斿畬鎴愭暟閲忔湭杈捐鍒掓暟閲忔椂鍙户缁垎鎵规姤宸�
           disabled: row =>
             row.completeQuantity >= row.planQuantity ||
-            !canCurrentUserReport(row) ||
-            row.hasUnreportedMachine,
+            !canCurrentUserReport(row),
         },
         {
           name: "鐢熶骇鎺掍骇",
@@ -1215,6 +1221,31 @@
     productMainId: null,
     teamList: [],
     deviceId: null,
+  });
+  // 鐝粍浜哄憳浜ч噺鏃堕暱鏄庣粏 [{ userId, userName, quantity, workHour }]
+  const personList = ref([]);
+  const teamSelectOptions = computed(() => {
+    const base =
+      Array.isArray(reportForm.userIdsList) && reportForm.userIdsList.length > 0
+        ? reportForm.userIdsList.map(u => ({
+            userId: String(u.userId ?? ""),
+            nickName: String(u.nickName ?? "").trim(),
+          }))
+        : [];
+    const baseNameSet = new Set(base.map(u => u.nickName));
+    const selected = Array.isArray(reportForm.teamList)
+      ? reportForm.teamList
+      : [];
+    const extraNames = selected
+      .map(item => {
+        if (typeof item === "string") return String(item).trim();
+        const name = item?.userName ?? item?.nickName ?? "";
+        return String(name).trim();
+      })
+      .filter(Boolean)
+      .filter(name => !baseNameSet.has(name));
+    const extras = extraNames.map(name => ({ userId: "", nickName: name }));
+    return [...base, ...extras];
   });
   function removeLastFour(str) {
     if (!str) return ""; // 绌哄�间繚鎶�
@@ -1520,7 +1551,7 @@
       });
   };
 
-  const showReportDialog = row => {
+  const showReportDialog = async row => {
     currentReportRowData.value = row;
     reportForm.planQuantity = row.planQuantity - row.completeQuantity;
     reportForm.quantity = row.planQuantity - row.completeQuantity;
@@ -1533,7 +1564,7 @@
     reportForm.replenishQty = 0;
     reportForm.teamList = [];
     reportForm.scrapQty = 0;
-    reportForm.addQty = 0;
+    reportForm.addQty = row.processRouteAddNum ? Number(row.processRouteAddNum) : 0;
     reportForm.userIds = row.userIds || [];
 
     // 鍚堝苟宸ュ崟鎶ュ伐浜哄拰宸ュ簭鎶ュ伐浜猴紝鍘婚噸
@@ -1552,6 +1583,34 @@
         userId: item.userId,
         nickName: item.nickName,
       }));
+
+    // 鑾峰彇鎶ュ伐寮圭獥鏁版嵁锛屽甫鍑洪粯璁ょ彮缁勬垚鍛橈紙鍚堝苟鎺掍骇浜哄憳涓庢満鍙版搷浣滃憳锛屽幓閲嶏級
+    personList.value = [];
+    try {
+      const res = await getProductWorkOrderById(row.id);
+      const reportPersons = (Array.isArray(res?.data?.reportPersons)
+        ? res.data.reportPersons
+        : []
+      )
+        .filter(p => p && typeof p === "object")
+        .map(p => ({
+          userId: p.userId ?? p.id ?? "",
+          userName: String(p.userName || p.nickName || "").trim(),
+        }))
+        .filter(p => p.userName !== "");
+      personList.value = reportPersons.map(p => ({
+        userId: p.userId,
+        userName: p.userName,
+        quantity: null,
+        workHour: null,
+      }));
+      reportForm.teamList = reportPersons.map(p => ({
+        userId: p.userId,
+        userName: p.userName,
+      }));
+    } catch (err) {
+      console.error("鑾峰彇鎶ュ伐寮圭獥鏁版嵁澶辫触", err);
+    }
 
     nextTick(() => {
       reportFormRef.value?.clearValidate();
@@ -1624,10 +1683,23 @@
       //   return;
       // }
 
+      // 鏍¢獙鍚勭彮缁勪骇閲忎箣鍜岀瓑浜庢姤宸ユ�讳骇閲�
+      const personQuantityTotal = personList.value.reduce(
+        (sum, p) => sum + (Number(p.quantity) || 0),
+        0
+      );
+      if (personQuantityTotal !== quantity) {
+        ElMessageBox.alert("鍚勭彮缁勪骇閲忎箣鍜屽繀椤荤瓑浜庢姤宸ユ�讳骇閲�", "鎻愮ず", {
+          confirmButtonText: "纭畾",
+        });
+        return;
+      }
+
       const submitData = {
         ...reportForm,
         quantity: quantity,
         scrapQty: scrapQty,
+        personList: personList.value,
       };
       addProductMain(submitData).then(res => {
         if (res.code === 200) {
@@ -1675,13 +1747,39 @@
 
   const handleTeamListChange = val => {
     if (!Array.isArray(val)) return;
-    if (!val.some(item => typeof item === "string")) return;
-    reportForm.teamList = val.map(item => {
+    let hasString = false;
+    const newList = val.map(item => {
       if (typeof item === "string") {
+        hasString = true;
         return { userName: item };
       }
       return item;
     });
+
+    if (hasString) {
+      reportForm.teamList = newList;
+    }
+
+    // 瑙e喅 allow-create 鍦� multiple 妯″紡涓嬭緭鍏ユ鍐呭涓嶈嚜鍔ㄦ竻绌虹殑闂
+    setTimeout(() => {
+      if (teamSelectRef.value) {
+        // 1. 娓呴櫎鍐呴儴 query 鐘舵��
+        teamSelectRef.value.query = "";
+        if (teamSelectRef.value.states) {
+          teamSelectRef.value.states.query = "";
+          teamSelectRef.value.states.inputValue = "";
+        }
+        // 2. 寮哄埗娓呴櫎 DOM 杈撳叆妗嗙殑鍊�
+        const input = teamSelectRef.value.$el?.querySelector("input");
+        if (input) {
+          input.value = "";
+        }
+        // 3. 閽堝鏌愪簺鐗堟湰锛岄噸缃�変腑鏍囩鐨勫唴閮ㄥ亸绉伙紙闃叉杈撳叆妗嗚鎸ゅ崰锛�
+        if (typeof teamSelectRef.value.resetInputState === "function") {
+          teamSelectRef.value.resetInputState();
+        }
+      }
+    }, 50);
   };
   // 瀹℃牳浜�
   const handleReviewerIdChange = userId => {
@@ -1711,6 +1809,8 @@
 
   // 鍒ゆ柇褰撳墠鐢ㄦ埛鏄惁鑳芥帓浜�
   const canScheduleByWorkOrderNo = row => {
+    // 绠$悊鍛樺彲鎺掍骇
+    if (isAdminUser.value) return true;
     if (!row) return false;
 
     const uid = String(currentUserId.value || "");

--
Gitblit v1.9.3