From df76c64ca6a49dbff88ea972a68a02ce53ffdbe3 Mon Sep 17 00:00:00 2001
From: zhangwencui <1064582902@qq.com>
Date: 星期四, 04 六月 2026 16:59:17 +0800
Subject: [PATCH] 指标绑定选择产品时,加上工序选择框(过程检、出厂检),支持多选。出厂检验及指标维护给出厂检增加工序字段

---
 src/views/productionManagement/workOrder/index.vue | 1295 ++++++++++++++++++++++++++++++++++++++++++++++++++--------
 1 files changed, 1,102 insertions(+), 193 deletions(-)

diff --git a/src/views/productionManagement/workOrder/index.vue b/src/views/productionManagement/workOrder/index.vue
index ea1132b..9c62a41 100644
--- a/src/views/productionManagement/workOrder/index.vue
+++ b/src/views/productionManagement/workOrder/index.vue
@@ -13,7 +13,8 @@
         </div>
         <div class="search-item">
           <el-button type="primary"
-                     @click="handleQuery">鎼滅储</el-button>
+                     @click="handleQuery">鎼滅储
+          </el-button>
         </div>
       </div>
     </div>
@@ -38,30 +39,34 @@
                label-width="120px">
         <el-form-item label="璁″垝寮�濮嬫椂闂�">
           <el-date-picker v-model="editrow.planStartTime"
-                          type="date"
+                          type="datetime"
                           placeholder="璇烽�夋嫨"
-                          value-format="YYYY-MM-DD"
+                          value-format="YYYY-MM-DD HH:mm"
+                          format="YYYY-MM-DD HH:mm"
                           style="width: 300px" />
         </el-form-item>
         <el-form-item label="璁″垝缁撴潫鏃堕棿">
           <el-date-picker v-model="editrow.planEndTime"
-                          type="date"
+                          type="datetime"
                           placeholder="璇烽�夋嫨"
-                          value-format="YYYY-MM-DD"
+                          value-format="YYYY-MM-DD HH:mm"
+                          format="YYYY-MM-DD HH:mm"
                           style="width: 300px" />
         </el-form-item>
         <el-form-item label="瀹為檯寮�濮嬫椂闂�">
           <el-date-picker v-model="editrow.actualStartTime"
-                          type="date"
+                          type="datetime"
                           placeholder="璇烽�夋嫨"
-                          value-format="YYYY-MM-DD"
+                          value-format="YYYY-MM-DD HH:mm"
+                          format="YYYY-MM-DD HH:mm"
                           style="width: 300px" />
         </el-form-item>
         <el-form-item label="瀹為檯缁撴潫鏃堕棿">
           <el-date-picker v-model="editrow.actualEndTime"
-                          type="date"
+                          type="datetime"
                           placeholder="璇烽�夋嫨"
-                          value-format="YYYY-MM-DD"
+                          value-format="YYYY-MM-DD HH:mm"
+                          format="YYYY-MM-DD HH:mm"
                           style="width: 300px" />
         </el-form-item>
       </el-form>
@@ -161,87 +166,128 @@
       margin-bottom: 40px;">
         <el-button type="primary"
                    style="margin-top: 20px;"
-                   @click="printTransferCard">鎵撳嵃娴佽浆鍗�</el-button>
+                   @click="printTransferCard">鎵撳嵃娴佽浆鍗�
+        </el-button>
       </div>
     </el-dialog>
     <el-dialog v-model="reportDialogVisible"
-               :title="`鎶ュ伐(鏈哄彴:${currentReportRowData?.deviceName || '-'})`"
-               width="500px">
+               :title="`鎶ュ伐(宸ュ崟缂栧彿:${currentReportRowData?.workOrderNo || '-'})`"
+               width="1000px">
       <el-form ref="reportFormRef"
                :model="reportForm"
                :rules="reportFormRules"
                label-width="120px">
-        <el-form-item label="寰呯敓浜ф暟閲�">
-          <el-input v-model="reportForm.planQuantity"
-                    readonly
-                    style="width: 300px" />
-        </el-form-item>
-        <el-form-item label="鏈鐢熶骇鏁伴噺"
-                      prop="quantity">
-          <el-input v-model.number="reportForm.quantity"
-                    type="number"
-                    min="1"
-                    step="1"
-                    style="width: 300px"
-                    placeholder="璇疯緭鍏ユ湰娆$敓浜ф暟閲�"
-                    @input="handleQuantityInput" />
-        </el-form-item>
-        <el-form-item label="鎶ュ簾鏁伴噺"
-                      prop="scrapQty">
-          <el-input v-model.number="reportForm.scrapQty"
-                    type="number"
-                    min="0"
-                    step="1"
-                    style="width: 300px"
-                    placeholder="璇疯緭鍏ユ姤搴熸暟閲�"
-                    @input="handleScrapQtyInput" />
-        </el-form-item>
-        <el-form-item label="鐝粍淇℃伅">
-          <el-select v-model="reportForm.userId"
-                     style="width: 300px"
-                     placeholder="璇烽�夋嫨鐝粍淇℃伅"
-                     clearable
-                     filterable
-                     @change="handleUserChange">
-            <el-option v-for="user in userOptions"
-                       :key="user.userId"
-                       :label="user.nickName"
-                       :value="user.userId" />
-          </el-select>
-        </el-form-item>
-        <el-form-item label="寮�濮嬫椂闂�"
-                      prop="startTime">
-          <el-date-picker v-model="reportForm.startTime"
-                          type="datetime"
-                          value-format="YYYY-MM-DD HH:mm:ss"
-                          format="YYYY-MM-DD HH:mm:ss"
-                          style="width: 300px"
-                          placeholder="璇烽�夋嫨寮�濮嬫椂闂�"
-                          clearable />
-        </el-form-item>
-        <el-form-item label="缁撴潫鏃堕棿"
-                      prop="endTime">
-          <el-date-picker v-model="reportForm.endTime"
-                          type="datetime"
-                          value-format="YYYY-MM-DD HH:mm:ss"
-                          format="YYYY-MM-DD HH:mm:ss"
-                          style="width: 300px"
-                          placeholder="璇烽�夋嫨缁撴潫鏃堕棿"
-                          clearable />
-        </el-form-item>
-        <el-form-item label="瀹℃牳浜�" prop="auditUserId">
-          <el-select v-model="reportForm.auditUserId"
-                     style="width: 300px"
-                     placeholder="璇烽�夋嫨瀹℃牳浜�"
-                     clearable
-                     filterable
-                     @change="handleReviewerIdChange">
-            <el-option v-for="user in userOptions"
-                       :key="user.userId"
-                       :label="user.nickName"
-                       :value="user.userId" />
-          </el-select>
-        </el-form-item>
+        <el-row :gutter="20">
+          <el-col :span="12">
+            <el-form-item label="寰呯敓浜ф暟閲�">
+              <el-input v-model="reportForm.planQuantity"
+                        readonly
+                        disabled />
+            </el-form-item>
+          </el-col>
+          <el-col :span="12">
+            <el-form-item label="鏈鐢熶骇鏁伴噺"
+                          prop="quantity">
+              <el-input v-model.number="reportForm.quantity"
+                        type="number"
+                        min="1"
+                        step="1"
+                        placeholder="璇疯緭鍏ユ湰娆$敓浜ф暟閲�"
+                        style="width: 100%"
+                        :class="{ 'over-limit': reportForm.quantity > reportForm.planQuantity }"
+                        @input="handleQuantityInput" />
+            </el-form-item>
+          </el-col>
+          <el-col :span="12">
+            <el-form-item label="琛ヤ骇鏁伴噺"
+                          prop="replenishQty">
+              <el-input v-model.number="reportForm.replenishQty"
+                        type="number"
+                        min="0"
+                        step="1"
+                        placeholder="璇疯緭鍏ヨˉ浜ф暟閲�" />
+            </el-form-item>
+          </el-col>
+          <el-col :span="12">
+            <el-form-item label="鎶ュ簾鏁伴噺"
+                          prop="scrapQty">
+              <el-input v-model.number="reportForm.scrapQty"
+                        type="number"
+                        min="0"
+                        step="1"
+                        placeholder="璇疯緭鍏ユ姤搴熸暟閲�"
+                        @input="handleScrapQtyInput" />
+            </el-form-item>
+          </el-col>
+          <el-col :span="12">
+            <el-form-item label="鍔犳斁鏁�"
+                          prop="addQty">
+              <el-input v-model.number="reportForm.addQty"
+                        type="number"
+                        min="0"
+                        step="1"
+                        placeholder="璇疯緭鍏ュ姞鏀炬暟" />
+            </el-form-item>
+          </el-col>
+          <el-col :span="12">
+            <el-form-item label="鐝粍淇℃伅"
+                          prop="teamList">
+              <el-select v-model="reportForm.teamList"
+                         ref="teamSelectRef"
+                         multiple
+                         filterable
+                         allow-create
+                         default-first-option
+                         clearable
+                         collapse-tags
+                         value-key="userName"
+                         placeholder="璇烽�夋嫨鎴栬緭鍏ョ彮缁勬垚鍛�"
+                         @change="handleTeamListChange">
+                <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>
+            </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">-->
+          <!--              <el-select-->
+          <!--                  v-model="reportForm.auditUserId"-->
+          <!--                  placeholder="璇烽�夋嫨瀹℃牳浜�"-->
+          <!--                  clearable-->
+          <!--                  filterable-->
+          <!--                  @change="handleReviewerIdChange"-->
+          <!--              >-->
+          <!--                <el-option-->
+          <!--                    v-for="user in userOptions"-->
+          <!--                    :key="user.userId"-->
+          <!--                    :label="user.nickName"-->
+          <!--                    :value="user.userId"-->
+          <!--                />-->
+          <!--              </el-select>-->
+          <!--            </el-form-item>-->
+          <!--          </el-col>-->
+        </el-row>
       </el-form>
       <template #footer>
         <span class="dialog-footer">
@@ -251,36 +297,181 @@
         </span>
       </template>
     </el-dialog>
-    <el-dialog
-      v-model="auditDialogVisible"
-      title="瀹℃牳"
-      width="1000px"
-      :close-on-click-modal="false"
-    >
-      <el-table :data="auditTableData" border style="width: 100%" v-loading="auditLoading">
-        <el-table-column label="浜у搧鍚嶇О" prop="productName" min-width="140" show-overflow-tooltip />
-        <el-table-column label="瑙勬牸" prop="model" min-width="120" show-overflow-tooltip />
-        <el-table-column label="鍗曚綅" prop="unit" width="80" />
-        <el-table-column label="宸ュ簭鍚嶇О" prop="processName" min-width="120" show-overflow-tooltip />
-        <el-table-column label="闇�姹傛暟閲�" prop="planQuantity" width="110" />
-        <el-table-column label="瀹屾垚鏁伴噺" prop="completeQuantity" width="110" />
-        <el-table-column label="瀹屾垚杩涘害" prop="completionStatus" width="140">
+    <el-dialog v-model="auditDialogVisible"
+               title="瀹℃牳"
+               width="1000px"
+               :close-on-click-modal="false">
+      <el-table :data="auditTableData"
+                border
+                style="width: 100%"
+                v-loading="auditLoading">
+        <el-table-column label="浜у搧鍚嶇О"
+                         prop="productName"
+                         min-width="140"
+                         show-overflow-tooltip />
+        <el-table-column label="瑙勬牸"
+                         prop="model"
+                         min-width="120"
+                         show-overflow-tooltip />
+        <el-table-column label="鍗曚綅"
+                         prop="unit"
+                         width="80" />
+        <el-table-column label="宸ュ簭鍚嶇О"
+                         prop="processName"
+                         min-width="120"
+                         show-overflow-tooltip />
+        <el-table-column label="闇�姹傛暟閲�"
+                         prop="planQuantity"
+                         width="110" />
+        <el-table-column label="瀹屾垚鏁伴噺"
+                         prop="completeQuantity"
+                         width="110" />
+        <el-table-column label="瀹屾垚杩涘害"
+                         prop="completionStatus"
+                         width="140">
           <template #default="{ row }">
-            <el-progress
-              :percentage="toProgressPercentage(row?.completionStatus)"
-              :color="progressColor(toProgressPercentage(row?.completionStatus))"
-              :status="toProgressPercentage(row?.completionStatus) >= 100 ? 'success' : ''"
-            />
+            <el-progress :percentage="toProgressPercentage(row?.completionStatus)"
+                         :color="progressColor(toProgressPercentage(row?.completionStatus))"
+                         :status="toProgressPercentage(row?.completionStatus) >= 100 ? 'success' : ''" />
           </template>
         </el-table-column>
-        <el-table-column label="璁″垝寮�濮嬫椂闂�" prop="planStartTime" width="140" />
-        <el-table-column label="璁″垝缁撴潫鏃堕棿" prop="planEndTime" width="140" />
+        <el-table-column label="璁″垝寮�濮嬫椂闂�"
+                         prop="planStartTime"
+                         width="140" />
+        <el-table-column label="璁″垝缁撴潫鏃堕棿"
+                         prop="planEndTime"
+                         width="140" />
       </el-table>
       <template #footer>
         <span class="dialog-footer">
-          <el-button type="primary" :loading="auditLoading" @click="submitAudit(1)">閫氳繃</el-button>
-          <el-button type="danger" :loading="auditLoading" @click="submitAudit(2)">涓嶉�氳繃</el-button>
-          <el-button :disabled="auditLoading" @click="auditDialogVisible = false">鍙栨秷</el-button>
+          <el-button type="primary"
+                     :loading="auditLoading"
+                     @click="submitAudit(1)">閫氳繃</el-button>
+          <el-button type="danger"
+                     :loading="auditLoading"
+                     @click="submitAudit(2)">涓嶉�氳繃</el-button>
+          <el-button :disabled="auditLoading"
+                     @click="auditDialogVisible = false">鍙栨秷</el-button>
+        </span>
+      </template>
+    </el-dialog>
+    <el-dialog v-model="scheduleDialogVisible"
+               :title="scheduleDialogTitle"
+               width="1000px"
+               :close-on-click-modal="false">
+      <div class="schedule-panel">
+        <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"
+                           :index="indexMethod" />
+          <el-table-column label="鏈涓婃満鏈哄彴"
+                           min-width="220">
+            <template #default="{ row }">
+              <el-select v-model="row.deviceId"
+                         placeholder="璇烽�夋嫨鏈哄彴"
+                         filterable
+                         clearable
+                         style="width: 100%"
+                         :disabled="scheduleSaving || isScheduleHistoryMode"
+                         @change="val => handleScheduleDeviceChange(val, row)">
+                <el-option v-for="item in deviceOptions"
+                           :key="item.id"
+                           :label="item.deviceName"
+                           :value="String(item.id)" />
+              </el-select>
+            </template>
+          </el-table-column>
+          <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
+                         multiple
+                         clearable
+                         collapse-tags
+                         style="width: 100%"
+                         :disabled="scheduleSaving"
+                         @change="val => handleScheduleUserChange(val, row)">
+                <el-option v-for="user in row.userOptions"
+                           :key="user.userId"
+                           :label="user.nickName"
+                           :value="String(user.userId)" />
+              </el-select>
+            </template>
+          </el-table-column>
+          <el-table-column label="鏈涓婃満鏃堕棿"
+                           min-width="240">
+            <template #default="{ row }">
+              <el-date-picker v-model="row.startTime"
+                              type="datetime"
+                              value-format="YYYY-MM-DD HH:mm:ss"
+                              format="YYYY-MM-DD HH:mm:ss"
+                              placeholder="璇烽�夋嫨涓婃満鏃堕棿"
+                              style="width: 100%"
+                              :disabled="scheduleSaving || isScheduleHistoryMode" />
+            </template>
+          </el-table-column>
+          <el-table-column v-if="!isScheduleHistoryMode"
+                           label="鎿嶄綔"
+                           width="110"
+                           align="center">
+            <template #default="{ row }">
+              <el-button link
+                         type="danger"
+                         :loading="row.deleting"
+                         :disabled="scheduleSaving"
+                         @click="removeScheduleRow(row)">
+                鍒犻櫎
+              </el-button>
+            </template>
+          </el-table-column>
+        </el-table>
+        <Pagination v-show="isScheduleHistoryMode && schedulePage.total > 0"
+                    style="margin-top: 12px"
+                    :total="schedulePage.total"
+                    :page="schedulePage.current"
+                    :limit="schedulePage.size"
+                    @pagination="handleSchedulePagination" />
+      </div>
+      <template #footer>
+        <span class="dialog-footer">
+          <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>
@@ -289,20 +480,554 @@
 </template>
 
 <script setup>
-  import { onMounted, ref, nextTick } from "vue";
+  import { onMounted, ref, nextTick, computed } from "vue";
+  import { deepClone } from "@/utils/index.js";
   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,
     addProductMain,
     downProductWorkOrder,
+    addProductionMachineRecord,
+    productionMachineRecordListPage,
+    deleteProductionMachineRecord,
   } from "@/api/productionManagement/workOrder.js";
   import { getUserProfile, userListNoPageByTenantId } from "@/api/system/user.js";
   import QRCode from "qrcode";
   import { getCurrentInstance, reactive, toRefs } from "vue";
   import FilesDia from "./components/filesDia.vue";
+  import { getDeviceLedger } from "@/api/equipmentManagement/ledger.js";
+
   const { proxy } = getCurrentInstance();
+
+  const currentUserId = ref("");
+  const deviceOptions = ref([]);
+  const currentUserName = ref("");
+  const teamSelectRef = ref(null);
+
+  const ensureCurrentUser = async () => {
+    if (currentUserId.value) return;
+    try {
+      const res = await getUserProfile();
+      if (res?.code === 200) {
+        currentUserId.value = String(res?.data?.userId ?? "");
+        currentUserName.value = String(res?.data?.nickName ?? "");
+      }
+    } catch (err) {
+      console.error("鑾峰彇鐢ㄦ埛淇℃伅澶辫触", err);
+    }
+  };
+
+  // 鏈哄彴鑾峰彇
+  const getDeviceList = () => {
+    getDeviceLedger().then(res => {
+      deviceOptions.value = Array.isArray(res?.data) ? res.data : [];
+    });
+  };
+
+  const handleDeviceChange = val => {
+    const device = deviceOptions.value.find(item => item.id === val);
+    reportForm.deviceName = device?.deviceName || "";
+    reportForm.deviceId = val || "";
+  };
+
+  const normalizeArray = val => {
+    if (val === null || val === undefined) return [];
+    if (Array.isArray(val)) return val;
+    if (typeof val === "string") {
+      return val
+        .split(/[,锛�;锛沑s]+/g)
+        .map(s => s.trim())
+        .filter(Boolean);
+    }
+    return [val];
+  };
+
+  const isCurrentUserInUserIds = row => {
+    const uid = String(currentUserId.value || "");
+    if (!uid) return false;
+
+    const ids = normalizeArray(row?.userIds)
+      .map(id => String(id))
+      .filter(Boolean);
+
+    return ids.includes(uid);
+  };
+
+  // 鍒ゆ柇褰撳墠鐢ㄦ埛鏄惁鍦ㄥ伐搴忔姤宸ヤ汉涓�
+  const isCurrentUserInProcessUserIds = row => {
+    const uid = String(currentUserId.value || "");
+    if (!uid) return false;
+
+    const ids = normalizeArray(row?.processUserIds)
+      .map(id => String(id))
+      .filter(Boolean);
+
+    return ids.includes(uid);
+  };
+
+  // 鍒ゆ柇褰撳墠鐢ㄦ埛鏄惁鍙互鎶ュ伐锛堝伐鍗曟姤宸ヤ汉 鎴� 宸ュ簭鎶ュ伐浜猴級
+  const canCurrentUserReport = row => {
+    return isCurrentUserInUserIds(row) || isCurrentUserInProcessUserIds(row);
+  };
+
+  const canOperateByReportWorker = computed(() => {
+    return row => isCurrentUserReportWorker(row);
+  });
+
+  const isRowScheduled = row => {
+    const ids = normalizeArray(row?.userIds)
+      .map(val => String(val))
+      .filter(Boolean);
+    if (!ids.length) return false;
+    return ids.some(val => val !== "0");
+  };
+
+  const buildBaseScheduleUsersByRow = row => {
+    if (!row) return [];
+
+    if (Array.isArray(row?.reportWorkerList) && row.reportWorkerList.length > 0) {
+      const mapped = row.reportWorkerList
+        .map(item => {
+          const userId = String(item?.userId ?? item?.id ?? "").trim();
+          const nickName = String(item?.userName ?? item?.nickName ?? "").trim();
+          return { userId, nickName: nickName || userId };
+        })
+        .filter(item => item.userId);
+      const uniq = new Map();
+      mapped.forEach(item => uniq.set(String(item.userId), item));
+      return Array.from(uniq.values());
+    }
+
+    const configuredIds = [
+      row.reportUserIds,
+      row.reportWorkerIds,
+      row.userIdList,
+      row.reportUserId,
+      row.userId,
+    ]
+      .flatMap(v => normalizeArray(v))
+      .map(v => String(v).trim())
+      .filter(Boolean);
+
+    if (configuredIds.length > 0) {
+      const uniqIds = Array.from(new Set(configuredIds));
+      return uniqIds.map(id => {
+        const user = userTeamOptions.value.find(
+          u => String(u.userId) === String(id)
+        );
+        return { userId: String(id), nickName: user?.nickName || String(id) };
+      });
+    }
+
+    return userTeamOptions.value.map(u => ({
+      userId: String(u.userId),
+      nickName: u.nickName,
+    }));
+  };
+
+  const resolveScheduleUserName = userId => {
+    const uid = String(userId ?? "").trim();
+    if (!uid) return "";
+    const inBase = baseScheduleUsers.value.find(u => String(u.userId) === uid);
+    if (inBase?.nickName) return inBase.nickName;
+    const inTeam = userTeamOptions.value.find(u => String(u.userId) === uid);
+    return inTeam?.nickName || uid;
+  };
+
+  const buildScheduleUserOptionsByDeviceId = deviceId => {
+    const device = deviceOptions.value.find(
+      item => String(item.id) === String(deviceId)
+    );
+
+    const operatorIds = device?.operatorId
+      ? String(device.operatorId)
+          .split(/[,锛�;锛沑s]+/g)
+          .map(id => id.trim())
+          .filter(Boolean)
+      : [];
+
+    if (!operatorIds.length) {
+      return [...baseScheduleUsers.value];
+    }
+
+    return baseScheduleUsers.value.filter(user =>
+      operatorIds.includes(String(user.userId))
+    );
+  };
+
+  const createScheduleRow = (preset = {}) => {
+    const deviceId =
+      preset?.deviceId === null || preset?.deviceId === undefined
+        ? ""
+        : String(preset.deviceId);
+
+    const userOptions = deviceId
+      ? buildScheduleUserOptionsByDeviceId(deviceId)
+      : [...baseScheduleUsers.value];
+
+    const userIds = normalizeArray(preset?.userIds)
+      .map(val => String(val))
+      .filter(Boolean)
+      .filter(uid =>
+        userOptions.some(user => String(user.userId) === String(uid))
+      );
+
+    return {
+      id: preset?.id ?? "",
+      deviceId,
+      deviceName: preset?.deviceName ?? "",
+      userIds,
+      userOptions,
+      startTime: preset?.startTime ?? dayjs().format("YYYY-MM-DD HH:mm:ss"),
+      deleting: false,
+    };
+  };
+
+  const addScheduleRow = preset => {
+    if (preset) {
+      scheduleRows.value.push(createScheduleRow(preset));
+      return;
+    }
+
+    scheduleRows.value.push(
+      createScheduleRow({
+        id: "",
+        deviceId: "",
+        deviceName: "",
+        userIds: [],
+        startTime: dayjs().format("YYYY-MM-DD HH:mm:ss"),
+      })
+    );
+  };
+
+  const refreshScheduleRows = async () => {
+    const workOrderRow = currentReportRowData.value;
+
+    if (!workOrderRow?.id) {
+      schedulePage.current = 1;
+      schedulePage.total = 0;
+      scheduleRows.value = [];
+      return;
+    }
+
+    scheduleLoading.value = true;
+    try {
+      const res = await productionMachineRecordListPage({
+        workOrderId: workOrderRow.id,
+        current: schedulePage.current,
+        size: schedulePage.size,
+      });
+
+      const records = Array.isArray(res?.data?.records) ? res.data.records : [];
+      const apiTotal = Number(res?.data?.total);
+      schedulePage.total =
+        Number.isFinite(apiTotal) && apiTotal > 0 ? apiTotal : records.length;
+
+      const lastPage = Math.max(
+        1,
+        Math.ceil((schedulePage.total || 0) / schedulePage.size)
+      );
+      if (schedulePage.current > lastPage) {
+        schedulePage.current = lastPage;
+        await refreshScheduleRows();
+        return;
+      }
+
+      const rows = records.map(record => mapMachineRecordToScheduleRow(record));
+      scheduleRows.value = rows;
+    } catch (error) {
+      console.error("鑾峰彇鎺掍骇璁板綍澶辫触", error);
+      schedulePage.total = 0;
+      scheduleRows.value = [];
+      ElMessage.error("鑾峰彇鎺掍骇璁板綍澶辫触");
+    } finally {
+      scheduleLoading.value = false;
+    }
+  };
+
+  const removeScheduleRow = async row => {
+    if (!row || isScheduleHistoryMode.value) return;
+
+    if (!row.id) {
+      scheduleRows.value = scheduleRows.value.filter(item => item !== row);
+      if (!scheduleRows.value.length) {
+        addScheduleRow();
+      }
+      return;
+    }
+
+    try {
+      await ElMessageBox.confirm("纭畾鍒犻櫎杩欐潯鎺掍骇璁板綍鍚楋紵", "鎻愮ず", {
+        confirmButtonText: "纭畾",
+        cancelButtonText: "鍙栨秷",
+        type: "warning",
+      });
+    } catch {
+      return;
+    }
+
+    row.deleting = true;
+    try {
+      const res = await deleteProductionMachineRecord([row.id]);
+      if (res?.code !== undefined && res.code !== 200) {
+        ElMessage.error(res?.msg || "鍒犻櫎澶辫触");
+        return;
+      }
+
+      ElMessage.success("鍒犻櫎鎴愬姛");
+      await refreshScheduleRows();
+      getList();
+    } catch (error) {
+      console.error("鍒犻櫎鎺掍骇璁板綍澶辫触", error);
+      ElMessage.error("鍒犻櫎澶辫触锛岃閲嶈瘯");
+    } finally {
+      row.deleting = false;
+    }
+  };
+
+  const handleScheduleUserChange = (userIds, row) => {
+    row.userIds = normalizeArray(userIds)
+      .map(val => String(val))
+      .filter(Boolean);
+  };
+
+  const handleScheduleDeviceChange = (deviceId, row) => {
+    const device = deviceOptions.value.find(
+      item => String(item.id) === String(deviceId)
+    );
+
+    row.deviceId =
+      deviceId === null || deviceId === undefined ? "" : String(deviceId);
+    row.deviceName = device?.deviceName || "";
+    row.userOptions = row.deviceId
+      ? buildScheduleUserOptionsByDeviceId(row.deviceId)
+      : [...baseScheduleUsers.value];
+
+    row.userIds = normalizeArray(row.userIds)
+      .map(uid => String(uid))
+      .filter(uid =>
+        row.userOptions.some(user => String(user.userId) === String(uid))
+      );
+  };
+
+  const handleSchedulePagination = ({ page, limit }) => {
+    if (!isScheduleHistoryMode.value) return;
+    schedulePage.current = page;
+    schedulePage.size = limit;
+    refreshScheduleRows();
+  };
+
+  const validateScheduleRows = () => {
+    if (!scheduleRows.value.length) {
+      ElMessage.warning("璇疯嚦灏戞坊鍔犱竴鏉′笂鏈轰俊鎭�");
+      return false;
+    }
+
+    for (let index = 0; index < scheduleRows.value.length; index += 1) {
+      const row = scheduleRows.value[index];
+
+      if (!row.deviceId) {
+        ElMessage.warning(`绗�${index + 1}琛岃閫夋嫨鏈哄彴`);
+        return false;
+      }
+
+      if (!Array.isArray(row.userIds) || row.userIds.length === 0) {
+        ElMessage.warning(`绗�${index + 1}琛岃閫夋嫨涓婃満浜篳);
+        return false;
+      }
+
+      if (!row.startTime) {
+        ElMessage.warning(`绗�${index + 1}琛岃閫夋嫨涓婃満鏃堕棿`);
+        return false;
+      }
+
+      if (!dayjs(row.startTime).isValid()) {
+        ElMessage.warning(`绗�${index + 1}琛屼笂鏈烘椂闂存牸寮忎笉姝g‘`);
+        return false;
+      }
+    }
+
+    return true;
+  };
+
+  const buildMachineRecordPayload = (
+    workOrderRow,
+    scheduleRow,
+    sortIndex = 0
+  ) => {
+    const processId =
+      workOrderRow?.processId ??
+      workOrderRow?.productProcessRouteItemId ??
+      reportForm.productProcessRouteItemId;
+
+    const operatorIds = normalizeArray(scheduleRow?.userIds)
+      .map(val => String(val).trim())
+      .filter(Boolean)
+      .join(",");
+
+    const nickName = normalizeArray(scheduleRow?.userIds)
+      .map(uid => resolveScheduleUserName(uid))
+      .filter(Boolean)
+      .join(",");
+
+    const payload = {
+      workOrderId: workOrderRow?.id,
+      processId,
+      machineId: scheduleRow.deviceId ? Number(scheduleRow.deviceId) : undefined,
+      deviceName: scheduleRow.deviceName,
+      operatorId: operatorIds || undefined,
+      nickName: nickName || "",
+      machineStartTime: scheduleRow.startTime,
+      reportStatus: false,
+      remark: `鎺掍骇搴忓彿:${sortIndex + 1}`,
+    };
+
+    if (scheduleRow.id) {
+      payload.id = scheduleRow.id;
+    }
+
+    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 ?? "";
+    const deviceName = record?.deviceName ?? record?.machineName ?? "";
+    const startTime = record?.machineStartTime ?? record?.startTime ?? "";
+    const userIds = normalizeArray(
+      record?.operatorId ?? record?.operatorIds ?? record?.userId
+    )
+      .map(val => String(val))
+      .filter(Boolean);
+
+    return createScheduleRow({
+      id,
+      deviceId:
+        deviceId === null || deviceId === undefined ? "" : String(deviceId),
+      deviceName,
+      userIds,
+      startTime,
+    });
+  };
+
+  const buildScheduleRowsFromRecords = records => {
+    const list = Array.isArray(records) ? records : [];
+    const grouped = new Map();
+
+    list.forEach(record => {
+      const row = mapMachineRecordToScheduleRow(record);
+      const key = `${row.deviceId}__${row.startTime}__${row.deviceName}`;
+
+      if (!grouped.has(key)) {
+        grouped.set(key, row);
+        return;
+      }
+
+      const existing = grouped.get(key);
+      existing.ids = Array.from(new Set([existing.id, row.id].filter(Boolean)));
+      existing.userIds = Array.from(
+        new Set(
+          [...(existing?.userIds || []), ...(row?.userIds || [])].map(v =>
+            String(v)
+          )
+        )
+      ).filter(Boolean);
+
+      if (!existing.deviceName && row.deviceName)
+        existing.deviceName = row.deviceName;
+    });
+
+    return Array.from(grouped.values()).sort(
+      (a, b) => dayjs(a.startTime).valueOf() - dayjs(b.startTime).valueOf()
+    );
+  };
+
+  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;
+
+    await refreshScheduleRows();
+  };
+
+  const handleSaveSchedule = async () => {
+    if (isScheduleHistoryMode.value) return;
+    if (scheduleSaving.value) return;
+    if (!validateScheduleRows()) return;
+
+    const workOrderRow = currentReportRowData.value;
+    if (!workOrderRow?.id) {
+      ElMessage.warning("缂哄皯宸ュ崟淇℃伅锛屾棤娉曚繚瀛樻帓浜�");
+      return;
+    }
+
+    const sortedRows = [...scheduleRows.value].sort(
+      (a, b) => dayjs(a.startTime).valueOf() - dayjs(b.startTime).valueOf()
+    );
+
+    scheduleSaving.value = true;
+    try {
+      const productionMachineRecord = sortedRows.map((scheduleRow, index) =>
+        buildMachineRecordPayload(workOrderRow, scheduleRow, index)
+      );
+
+      const res = await addProductionMachineRecord({ productionMachineRecord });
+      if (res?.code !== undefined && res.code !== 200) {
+        ElMessage.error(res?.msg || "淇濆瓨鎺掍骇澶辫触");
+        return;
+      }
+
+      proxy.$modal.msgSuccess("鎺掍骇宸蹭繚瀛�");
+      scheduleDialogVisible.value = false;
+      resetCreateScheduleRows();
+      await getList();
+    } catch (error) {
+      console.error("淇濆瓨鎺掍骇澶辫触", error);
+      ElMessage.error("淇濆瓨鎺掍骇澶辫触锛岃閲嶈瘯");
+    } finally {
+      scheduleSaving.value = false;
+    }
+  };
 
   const tableColumn = ref([
     {
@@ -319,27 +1044,30 @@
       label: "鐢熶骇璁㈠崟鍙�",
       prop: "productOrderNpsNo",
       width: "140",
+      formatData: val => (val && val.length > 4 ? val.slice(0, -4) : val || ""),
     },
     {
-      label: "浜у搧鍚嶇О",
-      prop: "productName",
-      width: "140",
+      label: "鎴愬搧鍚嶇О",
+      prop: "finalProductModel",
+      minWidth: 200,
+      overHidden: false,
     },
-    {
-      label: "瑙勬牸",
-      prop: "model",
-    },
-    {
-      label: "鍗曚綅",
-      prop: "unit",
-    },
+    // {
+    //   label: "鍔犲伐鍝佸悕绉�",
+    //   prop: "productName",
+    //   width: "140",
+    // },
+    // {
+    //   label: "鍔犲伐鍝佽鏍�",
+    //   prop: "model",
+    // },
+    // {
+    //   label: "鍔犲伐鍝佸崟浣�",
+    //   prop: "unit",
+    // },
     {
       label: "宸ュ簭鍚嶇О",
       prop: "processName",
-    },
-    {
-      label: "鏈哄彴鍚嶇О",
-      prop: "deviceName",
     },
     {
       label: "闇�姹傛暟閲�",
@@ -380,7 +1108,7 @@
     },
     {
       label: "鎿嶄綔",
-      width: "200",
+      width: "220",
       align: "center",
       dataType: "action",
       fixed: "right",
@@ -390,8 +1118,6 @@
           clickFun: row => {
             handleEdit(row);
           },
-          // 褰撻渶姹傛暟閲忕瓑浜庡畬鎴愭暟閲忕殑鏃跺�欙紝鎸夐挳涓嶅彲鐐瑰嚮
-          disabled: row => Number(row?.planQuantity) === Number(row?.completeQuantity),
         },
         {
           name: "娴佽浆鍗�",
@@ -410,7 +1136,34 @@
           clickFun: row => {
             showReportDialog(row);
           },
-          disabled: row => Number(row?.planQuantity) <= Number(row?.completeQuantity) || row.planQuantity <= 0,
+          // 鐢ㄦ埛褰撳墠id鍦ㄥ伐鍗曟姤宸ヤ汉鎴栧伐搴忔姤宸ヤ汉涓�
+          disabled: row =>
+            row.completeQuantity >= row.planQuantity ||
+            !canCurrentUserReport(row) ||
+            row.hasUnreportedMachine,
+        },
+        {
+          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:"瀹℃牳",
@@ -425,13 +1178,21 @@
   ]);
   const tableData = ref([]);
   const tableLoading = ref(false);
-  const qrCodeUrl = ref("");
-  const qrRowData = ref(null);
+  const scheduleRows = ref([]);
+  const scheduleLoading = ref(false);
+  const scheduleSaving = ref(false);
+  const schedulePage = reactive({
+    current: 1,
+    size: 10,
+    total: 0,
+  });
   const editDialogVisible = ref(false);
   const transferCardVisible = ref(false);
-  const transferCardData = ref([]);
   const transferCardQrUrl = ref("");
+  const scheduleDialogVisible = ref(false);
   const transferCardRowData = ref(null);
+  const baseScheduleUsers = ref([]);
+  const userTemp = ref([]);
   const reportDialogVisible = ref(false);
   const auditDialogVisible = ref(false);
   const auditRowData = ref(null);
@@ -440,10 +1201,12 @@
   const workOrderFilesRef = ref(null);
   const reportFormRef = ref(null);
   const userOptions = ref([]);
+  const userTeamOptions = ref([]);
   const reportForm = reactive({
     planQuantity: 0,
     quantity: null,
     scrapQty: null,
+    addQty: 0,
     startTime: "",
     endTime: "",
     userName: "",
@@ -452,8 +1215,36 @@
     productProcessRouteItemId: "",
     userId: "",
     productMainId: null,
+    teamList: [],
+    deviceId: null,
   });
-
+  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 ""; // 绌哄�间繚鎶�
+    return str.toString().slice(0, -4); // 鏍稿績锛氭埅鍙� 0 鍒� 鍊掓暟绗�4浣�
+  }
   // 鏈鐢熶骇鏁伴噺楠岃瘉瑙勫垯
   const validateQuantity = (rule, value, callback) => {
     if (value === null || value === undefined || value === "") {
@@ -485,7 +1276,7 @@
   };
 
   // 瀹℃牳
-  const handleAudit = (row) => {
+  const handleAudit = row => {
     if (Number(row?.auditStatus) === 1) {
       ElMessage.warning("璇ュ伐鍗曞凡瀹℃牳");
       return;
@@ -499,7 +1290,7 @@
     auditDialogVisible.value = true;
   };
 
-  const submitAudit = async (result) => {
+  const submitAudit = async result => {
     const current = auditRowData.value;
     if (!current) return;
     if (auditLoading.value) return;
@@ -525,20 +1316,20 @@
       await Promise.all(updates);
       ElMessage.success("瀹℃牳鎴愬姛");
       auditDialogVisible.value = false;
-      getList();
+      await getList();
     } finally {
       auditLoading.value = false;
     }
   };
 
   // 鏌ョ湅璇︽儏
-  const handleView = (row) => {
+  const handleView = row => {
     const { workOrderId } = row;
     router.push({
       path: "/productionManagement/workOrderDetail",
       query: { workOrderId },
     });
-  }
+  };
 
   // 楠岃瘉瑙勫垯
   const reportFormRules = {
@@ -546,7 +1337,9 @@
     scrapQty: [{ validator: validateScrapQty, trigger: "blur" }],
     startTime: [{ required: true, message: "璇烽�夋嫨寮�濮嬫椂闂�", trigger: "change" }],
     endTime: [{ required: true, message: "璇烽�夋嫨缁撴潫鏃堕棿", trigger: "change" }],
-    auditUserId: [{ required: true, message: "璇烽�夋嫨瀹℃牳浜�", trigger: "change" }],
+    // auditUserId: [{required: true, message: "璇烽�夋嫨瀹℃牳浜�", trigger: "change"}],
+    teamList: [{ required: true, message: "璇烽�夋嫨鐝粍", trigger: "change" }],
+    deviceId: [{ required: true, message: "璇烽�夋嫨璁惧", trigger: "change" }],
   };
 
   // 澶勭悊鏈鐢熶骇鏁伴噺杈撳叆锛岄檺鍒跺繀椤诲ぇ浜庣瓑浜�1
@@ -642,18 +1435,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;
+    }
   };
 
   // 涓嬭浇骞舵墦鍗板伐鍗曟祦杞崱锛堟枃浠舵祦锛�
@@ -721,6 +1523,10 @@
   };
 
   const handleEdit = row => {
+    // if (!isCurrentUserReportWorker(row)) {
+    //   ElMessage.warning("褰撳墠鐢ㄦ埛涓嶆槸璇ュ伐鍗曠殑鎶ュ伐浜猴紝鏃犳硶缂栬緫");
+    //   return;
+    // }
     editrow.value = JSON.parse(JSON.stringify(row));
     editDialogVisible.value = true;
   };
@@ -740,33 +1546,45 @@
   };
 
   const showReportDialog = row => {
-    const nowTime = dayjs().format("YYYY-MM-DD HH:mm:ss");
     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;
     reportForm.productMainId = row.productMainId;
-    reportForm.startTime = nowTime;
-    reportForm.endTime = nowTime;
-    reportForm.scrapQty =
-      row.scrapQty !== undefined && row.scrapQty !== null ? row.scrapQty : null;
+    reportForm.startTime = "";
+    reportForm.endTime = "";
+    reportForm.replenishQty = 0;
+    reportForm.teamList = [];
+    reportForm.scrapQty = 0;
+    reportForm.addQty = 0;
+    reportForm.userIds = row.userIds || [];
+
+    // 鍚堝苟宸ュ崟鎶ュ伐浜哄拰宸ュ簭鎶ュ伐浜猴紝鍘婚噸
+    const workOrderUserIds = normalizeArray(row.userIds)
+      .map(id => String(id).trim())
+      .filter(Boolean);
+    const processUserIds = normalizeArray(row.processUserIds)
+      .map(id => String(id).trim())
+      .filter(Boolean);
+    const allowedUserIds = [...new Set([...workOrderUserIds, ...processUserIds])];
+
+    // 鍙厑璁搁�夋嫨宸ュ崟鎶ュ伐浜哄拰宸ュ簭鎶ュ伐浜�
+    reportForm.userIdsList = userTeamOptions.value
+      .filter(item => allowedUserIds.includes(String(item.userId)))
+      .map(item => ({
+        userId: item.userId,
+        nickName: item.nickName,
+      }));
+
     nextTick(() => {
       reportFormRef.value?.clearValidate();
     });
-    // 鑾峰彇褰撳墠鐧诲綍鐢ㄦ埛淇℃伅锛岃缃负榛樿閫変腑
-    getUserProfile()
-      .then(res => {
-        if (res.code === 200) {
-          reportForm.userId = res.data.userId;
-          reportForm.userName = res.data.nickName;
-        }
-      })
-      .catch(err => {
-        console.error("鑾峰彇鐢ㄦ埛淇℃伅澶辫触", err);
-      });
+    ensureCurrentUser().then(() => {
+      reportForm.userId = currentUserId.value;
+      reportForm.userName = currentUserName.value;
+    });
 
     reportDialogVisible.value = true;
   };
@@ -824,34 +1642,18 @@
         return;
       }
 
-      if (quantity > reportForm.planQuantity) {
-        ElMessageBox.alert("鏈鐢熶骇鏁伴噺涓嶈兘瓒呰繃寰呯敓浜ф暟閲�", "鎻愮ず", {
-          confirmButtonText: "纭畾",
-        });
-        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;
-      }
+      // if (quantity > reportForm.planQuantity) {
+      //   ElMessageBox.alert("鏈鐢熶骇鏁伴噺涓嶈兘瓒呰繃寰呯敓浜ф暟閲�", "鎻愮ず", {
+      //     confirmButtonText: "纭畾",
+      //   });
+      //   return;
+      // }
 
       const submitData = {
         ...reportForm,
         quantity: quantity,
         scrapQty: scrapQty,
       };
-
-      // console.log(submitData);
       addProductMain(submitData).then(res => {
         if (res.code === 200) {
           proxy.$modal.msgSuccess("鎶ュ伐鎴愬姛");
@@ -871,7 +1673,12 @@
     userListNoPageByTenantId()
       .then(res => {
         if (res.code === 200) {
-          userOptions.value = res.data || [];
+          const list = Array.isArray(res.data) ? res.data : [];
+          userOptions.value = [
+            { nickName: "浠绘剰鐢ㄦ埛", userId: "-1" },
+            ...deepClone(list),
+          ];
+          userTeamOptions.value = deepClone(list);
         }
       })
       .catch(err => {
@@ -890,6 +1697,43 @@
       reportForm.userName = "";
     }
   };
+
+  const handleTeamListChange = val => {
+    if (!Array.isArray(val)) return;
+    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 => {
     if (userId) {
@@ -900,21 +1744,60 @@
     } else {
       reportForm.auditUserName = "";
     }
-  }
+  };
 
-  onMounted(() => {
-    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();
   });
 </script>
 
 <style scoped lang="scss">
   .search_form {
     margin-bottom: 20px;
+
     .search-row {
       display: flex;
       gap: 20px;
       align-items: center;
+
       .search-item {
         display: flex;
         align-items: center;
@@ -934,26 +1817,32 @@
     display: flex;
     gap: 20px;
     height: 350px;
+
     .transfer-card-info {
       flex: 1;
       overflow: auto;
+
       .info-group {
         width: 50%;
         float: left;
       }
+
       .info-item {
         display: flex;
         margin-bottom: 15px;
+
         .info-label {
           width: 120px;
           font-weight: bold;
           margin-right: 20px;
         }
+
         .info-value {
           flex: 1;
         }
       }
     }
+
     .transfer-card-qr {
       width: 240px;
       display: flex;
@@ -962,9 +1851,17 @@
       justify-content: flex-start;
     }
   }
+
+  .schedule-user-tags {
+    display: flex;
+    flex-wrap: wrap;
+    gap: 8px;
+    min-height: 32px;
+    align-items: center;
+  }
 </style>
 
-<style  lang="scss">
+<style lang="scss">
   @media print {
     @page {
       size: landscape;
@@ -1012,20 +1909,24 @@
     }
     .transfer-card-info {
       flex: 1;
+
       .info-group {
         width: 100%;
         float: none;
         margin-bottom: 20px;
       }
+
       .info-item {
         display: flex;
         margin-bottom: 10px;
+
         .info-label {
           width: 100px;
           font-weight: bold;
           margin-right: 15px;
           white-space: nowrap;
         }
+
         .info-value {
           flex: 1;
           word-break: break-word;
@@ -1044,4 +1945,12 @@
       height: 140px !important;
     }
   }
+  .el-table .cell {
+    white-space: normal !important;
+    word-break: break-all;
+  }
+
+  .over-limit .el-input__inner {
+    color: #f56c6c !important;
+  }
 </style>

--
Gitblit v1.9.3