Ver código fonte

优化rfid识别

yangg 2 semanas atrás
pai
commit
9541692377
1 arquivos alterados com 492 adições e 133 exclusões
  1. 492 133
      src/views/system/borrow/component/CollectEquipment/index.vue

+ 492 - 133
src/views/system/borrow/component/CollectEquipment/index.vue

@@ -297,7 +297,20 @@
                 <el-row :gutter="16">
                     <el-col :span="24">
                         <div style="margin: 8px 0" v-if="!isView" >
-                            <el-input ref="returnSearchInputRef" :disabled="isView" v-model="returnSearchText" placeholder="请扫描设备条码添加" style="width: 300px" @keyup.enter.prevent="handleReturnScanSearch" />
+                            <textarea
+                                ref="returnSearchInputRef"
+                                v-model="returnSearchText"
+                                class="device-code-input"
+                                placeholder="设备编号(支持扫码枪/RFID批量录入)"
+                                :disabled="loading"
+                                autocomplete="off"
+                                rows="1"
+                                style="width: 300px; vertical-align: top;"
+                                @input="handleReturnDeviceInput"
+                                @keydown="handleReturnRFIDKeydown"
+                                @blur="handleReturnDeviceBlur"
+                                @keydown.enter.prevent="handleReturnDeviceEnter"
+                            ></textarea>
                             <el-button type="primary" style="margin-left: 16px" @click="handleAdd" :disabled="isView">手动归还</el-button>
                         </div>
                         <el-table :data="returnDeviceList" border style="width: 100%" >
@@ -716,6 +729,13 @@ const returnDeviceList = ref<DeviceListItem[]>([]);
 const returnAccessoryInfo = ref('');
 const returnRemark = ref('');
 const selectedDevices = ref<DeviceListItem[]>([]); // 添加选中设备列表
+// 归还流程 RFID高速扫码缓冲相关
+const returnRfidInputBuffer = ref('');
+let returnRfidInputTimer: ReturnType<typeof setTimeout> | null = null;
+// 记录归还流程最后一次输入时间,用于检测是否是高速扫码输入
+let returnLastInputTime = 0;
+// 记录归还流程连续输入次数,用于判断是否是扫码输入
+let returnConsecutiveInputCount = 0;
 
 // 备注显示值计算属性:查看模式下显示 problem_remarks[0],否则显示 returnRemark
 const displayReturnRemark = computed({
@@ -946,10 +966,30 @@ const clearRFIDInputTimer = () => {
   }
 };
 
+// 清理归还流程RFID输入定时器
+const clearReturnRFIDInputTimer = () => {
+  if (returnRfidInputTimer) {
+    clearTimeout(returnRfidInputTimer);
+    returnRfidInputTimer = null;
+  }
+};
+
 // 提交RFID缓冲区内容
 const submitRFIDBuffer = () => {
-  if (!readRuleConfig.value.enableRFIDBuffer) return;
-  if (!rfidInputBuffer.value) return;
+  if (!readRuleConfig.value.enableRFIDBuffer) {
+    // 如果未启用RFID缓冲,直接使用 searchText 进行搜索
+    if (searchText.value.trim()) {
+      handleScanSearch();
+    }
+    return;
+  }
+  if (!rfidInputBuffer.value) {
+    // 如果没有缓冲内容,使用 searchText 进行搜索
+    if (searchText.value.trim()) {
+      handleScanSearch();
+    }
+    return;
+  }
   const bufferedValue = rfidInputBuffer.value;
   rfidInputBuffer.value = '';
   clearRFIDInputTimer();
@@ -969,57 +1009,33 @@ const scheduleRFIDBufferSubmit = () => {
   }, delay);
 };
 
-// 处理设备输入(用于同步 textarea 内容到缓冲区,作为备用方案防止第一个字符丢失
+// 处理设备输入(用于同步 textarea 内容,仅在缓冲模式下使用
 const handleDeviceInput = () => {
-  // 如果 textarea 有内容但缓冲区为空,可能是第一个字符通过默认行为输入了
-  // 这种情况发生在:第一个字符没有被拦截(因为判断逻辑),但后续字符是高速输入
-  if (rfidInputBuffer.value === '' && searchText.value && searchText.value.length > 0) {
-    // 同步到缓冲区,确保内容不丢失
-    rfidInputBuffer.value = searchText.value;
-    // 如果内容长度大于1,说明已经有多个字符,可能是高速输入
-    if (searchText.value.length > 1) {
-      lastInputTime = Date.now();
-      consecutiveInputCount = searchText.value.length;
-    } else {
-      // 单个字符,初始化时间戳
-      lastInputTime = Date.now();
-      consecutiveInputCount = 1;
-    }
-  } else if (rfidInputBuffer.value && searchText.value !== rfidInputBuffer.value) {
-    // 如果缓冲区有内容但 textarea 内容不同,同步缓冲区内容到 textarea
-    // 这确保显示的内容与缓冲区一致
+  // 如果缓冲区有内容,确保 textarea 显示与缓冲区一致
+  // 这主要用于处理退格键等操作后的同步
+  if (rfidInputBuffer.value && searchText.value !== rfidInputBuffer.value) {
     searchText.value = rfidInputBuffer.value;
   }
+  // 注意:正常输入时,不干预 textarea 的内容,让默认行为处理
 };
 
 // 检测是否是高速扫码输入(通过输入速度判断)
-const isHighSpeedInput = (): boolean => {
+// 返回值:{ isHighSpeed: boolean, isFirstInput: boolean, isNormalInput: boolean, timeSinceLastInput: number }
+const checkInputSpeed = () => {
   const now = Date.now();
   const timeSinceLastInput = lastInputTime > 0 ? now - lastInputTime : 0;
-  lastInputTime = now;
-  
-  // 如果是第一次输入(lastInputTime 之前为 0),先假设可能是高速输入
-  // 等待第二个字符来判断
-  if (timeSinceLastInput === 0) {
-    return false; // 第一次输入,暂时返回 false,但会在 handleRFIDKeydown 中特殊处理
-  }
+  const isFirstInput = lastInputTime === 0;
   
-  // 如果输入间隔很短(小于配置的最小输入速度),认为是高速扫码
-  if (timeSinceLastInput < readRuleConfig.value.minInputSpeed && timeSinceLastInput > 0) {
-    consecutiveInputCount++;
-    return true;
-  }
-  
-  // 如果输入间隔较长,重置计数
-  if (timeSinceLastInput > 200) {
-    consecutiveInputCount = 0;
-    // 如果之前有缓冲内容,先提交
-    if (rfidInputBuffer.value) {
-      submitRFIDBuffer();
-    }
+  if (!isFirstInput) {
+    lastInputTime = now;
   }
   
-  return false;
+  return {
+    isFirstInput,
+    timeSinceLastInput,
+    isHighSpeed: timeSinceLastInput > 0 && timeSinceLastInput < readRuleConfig.value.minInputSpeed,
+    isNormalInput: timeSinceLastInput > 200
+  };
 };
 
 // 处理RFID键盘输入(高速扫码)
@@ -1036,12 +1052,8 @@ const handleRFIDKeydown = (event: KeyboardEvent) => {
   
   // 处理回车键
   if (event.key === 'Enter') {
-    // 如果有缓冲内容,提交缓冲
-    if (rfidInputBuffer.value) {
-      event.preventDefault();
-      submitRFIDBuffer();
-    }
-    // 否则让默认行为处理(触发 handleDeviceEnter)
+    // 回车键由 @keydown.enter.prevent="handleDeviceEnter" 处理
+    // 这里不处理,让 handleDeviceEnter 统一处理
     return;
   }
   
@@ -1059,38 +1071,57 @@ const handleRFIDKeydown = (event: KeyboardEvent) => {
   
   // 处理普通字符输入
   if (event.key.length === 1) {
-    // 检测是否是高速扫码输入
-    const isHighSpeed = isHighSpeedInput();
+    const inputInfo = checkInputSpeed();
+    const { isFirstInput, isHighSpeed, isNormalInput, timeSinceLastInput } = inputInfo;
+    
+    // 如果是第一次输入,不拦截,让默认行为处理,只记录时间戳
+    if (isFirstInput) {
+      lastInputTime = Date.now();
+      // 不拦截,让字符正常输入到 textarea
+      return;
+    }
     
-    // 判断是否是第一次输入(缓冲区为空且计数为0且时间戳为0)
-    const isFirstInput = rfidInputBuffer.value === '' && consecutiveInputCount === 0;
+    // 如果检测到是正常输入(间隔 > 200ms),处理之前的缓冲内容
+    if (isNormalInput) {
+      // 如果之前有缓冲内容,先提交
+      if (rfidInputBuffer.value) {
+        submitRFIDBuffer();
+      }
+      // 重置状态
+      consecutiveInputCount = 0;
+      lastInputTime = Date.now();
+      // 不拦截,让字符正常输入到 textarea
+      return;
+    }
     
-    // 如果是高速输入、已经有缓冲内容、或者第一次输入,使用缓冲模式
-    // 第一次输入时,先捕获到缓冲区,等待第二个字符来判断是否是高速输入
-    if (isHighSpeed || rfidInputBuffer.value || consecutiveInputCount > 0 || isFirstInput) {
+    // 如果检测到是高速输入(间隔 < 30ms),使用缓冲模式
+    if (isHighSpeed) {
       event.preventDefault();
       event.stopPropagation(); // 阻止事件冒泡,避免影响其他元素
-      rfidInputBuffer.value += event.key;
-      searchText.value = rfidInputBuffer.value;
       
-      // 如果是第一次输入,初始化时间戳
-      if (isFirstInput) {
-        lastInputTime = Date.now();
-        consecutiveInputCount = 1;
+      // 如果是第一次检测到高速输入(之前没有缓冲内容),需要将 textarea 中已有的内容也加入缓冲区
+      if (rfidInputBuffer.value === '' && searchText.value) {
+        // textarea 中已经有内容(第一个字符已经通过默认行为输入了)
+        // 将整个内容作为缓冲区的初始值,然后追加当前字符
+        rfidInputBuffer.value = searchText.value + event.key;
       } else {
-        consecutiveInputCount++;
+        // 否则直接追加当前字符
+        rfidInputBuffer.value += event.key;
       }
-      
+      searchText.value = rfidInputBuffer.value;
+      consecutiveInputCount++;
       scheduleRFIDBufferSubmit();
-    } else {
-      // 如果是正常输入且之前有缓冲内容,先提交缓冲内容
-      if (rfidInputBuffer.value) {
-        submitRFIDBuffer();
-        // 提交后,当前字符走默认行为(正常输入)
-        // 注意:这里不阻止默认行为,让字符正常输入到 textarea
-      }
-      // 否则让默认行为处理(正常输入)
+      return;
+    }
+    
+    // 如果输入间隔在 30-200ms 之间,可能是正常输入,不拦截
+    // 但如果之前有缓冲内容,说明高速输入已结束,先提交
+    if (rfidInputBuffer.value) {
+      submitRFIDBuffer();
+      consecutiveInputCount = 0;
     }
+    lastInputTime = Date.now();
+    // 不拦截,让字符正常输入到 textarea
   }
 };
 
@@ -1123,13 +1154,10 @@ const handleDeviceBlur = (event: FocusEvent) => {
 // 处理回车键
 const handleDeviceEnter = (event: KeyboardEvent) => {
   if (event.shiftKey) return;
-  if (readRuleConfig.value.enableRFIDBuffer) {
-    event.preventDefault();
-    submitRFIDBuffer();
-    return;
-  }
   event.preventDefault();
-  handleScanSearch();
+  // 无论是否启用RFID缓冲,都调用 submitRFIDBuffer
+  // submitRFIDBuffer 内部会判断是否有缓冲内容,如果没有则直接使用 searchText 搜索
+  submitRFIDBuffer();
 };
 
 // 分割多个设备编号(支持分隔符)
@@ -1160,7 +1188,7 @@ const splitDeviceCodes = (input: string): string[] => {
   return [trimmed];
 };
 
-// 处理扫码搜索(支持批量)
+// 处理扫码搜索(支持批量,优化并发请求
 const handleScanSearch = async (event?: Event) => {
     // 阻止默认行为,防止表单提交导致页面刷新
     if (event) {
@@ -1182,73 +1210,114 @@ const handleScanSearch = async (event?: Event) => {
     const codes = splitDeviceCodes(searchText.value);
     if (codes.length === 0) return;
     
+    // 去重处理,避免重复请求同一个设备编号
+    const uniqueCodes = Array.from(new Set(codes.map(code => code.trim()))).filter(Boolean);
+    if (uniqueCodes.length === 0) return;
+    
     loading.value = true;
     let successCount = 0;
     let failCount = 0;
+    const errorMessages: string[] = [];
     
     try {
-      // 批量处理设备编号
-      for (const code of codes) {
-        try {
-          const res = await deviceApi.GetList({ 
+      // 批量并发处理设备编号(使用 Promise.allSettled 确保所有请求都完成)
+      // 限制并发数量,避免同时发起过多请求
+      const batchSize = 10; // 每批处理10个
+      const batches: string[][] = [];
+      for (let i = 0; i < uniqueCodes.length; i += batchSize) {
+        batches.push(uniqueCodes.slice(i, i + batchSize));
+      }
+      
+      // 逐批处理,每批内部并发
+      for (const batch of batches) {
+        const promises = batch.map(async (code) => {
+          try {
+            const res = await deviceApi.GetList({ 
               page: 1, 
               limit: 1, 
-              code: code.trim(),
+              code: code,
               status: 1 
-          });
-          
-          if (res.data && res.data.length > 0) {
+            });
+            
+            if (res.data && res.data.length > 0) {
               const device = res.data[0];
               if (device.available_quantity <= 0) {
-                  ElMessage.warning(`设备 ${code} 当前无可用数量`);
-                  failCount++;
-                  continue;
+                return { success: false, code, message: `设备 ${code} 当前无可用数量` };
               }
               
               // 检查是否已存在
               const existingDevice = deviceList.value.find(d => d.device_no === device.id);
               if (existingDevice) {
-                  existingDevice.borrow_count++;
-                  successCount++;
+                existingDevice.borrow_count++;
+                return { success: true, code, device: null };
               } else {
-                  // 添加新设备到列表
-                  deviceList.value.push({
-                      device_no: device.id,
-                      device_code: device.code,
-                      device_type: device.category_name,
-                      device_name: device.name || '',
-                      borrow_count: 1,
-                      brand: device.brand ||device.device_brand || '',
-                      device_specification: device.specification,
-                      model: device.model || '',
-                      warehouse: device.warehouse,
-                      available_quantity:device.available_quantity
-                  });
-                  successCount++;
+                // 添加新设备到列表
+                const newDevice = {
+                  device_no: device.id,
+                  device_code: device.code,
+                  device_type: device.category_name,
+                  device_name: device.name || '',
+                  borrow_count: 1,
+                  brand: device.brand || device.device_brand || '',
+                  device_specification: device.specification,
+                  model: device.model || '',
+                  warehouse: device.warehouse,
+                  available_quantity: device.available_quantity
+                };
+                deviceList.value.push(newDevice);
+                return { success: true, code, device: newDevice };
               }
-          } else {
-              ElMessage.warning(`未找到设备编号: ${code}`);
+            } else {
+              return { success: false, code, message: `未找到设备编号: ${code}` };
+            }
+          } catch (error) {
+            console.error(`处理设备编号 ${code} 失败:`, error);
+            return { success: false, code, message: `处理设备编号 ${code} 失败` };
+          }
+        });
+        
+        // 等待当前批次完成
+        const results = await Promise.allSettled(promises);
+        
+        // 统计结果
+        results.forEach((result, index) => {
+          if (result.status === 'fulfilled') {
+            const { success, message } = result.value;
+            if (success) {
+              successCount++;
+            } else {
               failCount++;
+              if (message) {
+                errorMessages.push(message);
+              }
+            }
+          } else {
+            failCount++;
+            errorMessages.push(`处理设备编号 ${batch[index]} 时发生错误`);
           }
-        } catch (error) {
-          console.error(`处理设备编号 ${code} 失败:`, error);
-          failCount++;
-        }
+        });
       }
       
       // 显示批量处理结果
-      if (codes.length > 1) {
+      if (uniqueCodes.length > 1) {
         if (successCount > 0 && failCount === 0) {
           ElMessage.success(`成功添加 ${successCount} 个设备`);
         } else if (successCount > 0 && failCount > 0) {
           ElMessage.warning(`成功添加 ${successCount} 个设备,失败 ${failCount} 个`);
+          // 只显示前3个错误信息,避免消息过多
+          if (errorMessages.length > 0) {
+            console.warn('批量处理错误详情:', errorMessages.slice(0, 3));
+          }
         } else if (failCount > 0) {
           ElMessage.error(`添加失败,共 ${failCount} 个设备编号`);
         }
       } else if (successCount > 0) {
         ElMessage.success('设备已添加到列表');
+      } else if (failCount > 0 && errorMessages.length > 0) {
+        ElMessage.warning(errorMessages[0]);
       }
     } catch (error) {
+        console.error('批量处理设备失败:', error);
         ElMessage.error('搜索设备失败');
     } finally {
         searchText.value = ''; // 清空搜索框
@@ -1276,49 +1345,324 @@ const normalizeReturnStatus = (status?: { value?: number | string; label?: strin
   };
 };
 
-// 处理归还扫码搜索
+// 提交归还流程RFID缓冲区内容
+const submitReturnRFIDBuffer = () => {
+  if (!readRuleConfig.value.enableRFIDBuffer) {
+    // 如果未启用RFID缓冲,直接使用 returnSearchText 进行搜索
+    if (returnSearchText.value.trim()) {
+      handleReturnScanSearch();
+    }
+    return;
+  }
+  if (!returnRfidInputBuffer.value) {
+    // 如果没有缓冲内容,使用 returnSearchText 进行搜索
+    if (returnSearchText.value.trim()) {
+      handleReturnScanSearch();
+    }
+    return;
+  }
+  const bufferedValue = returnRfidInputBuffer.value;
+  returnRfidInputBuffer.value = '';
+  clearReturnRFIDInputTimer();
+  returnConsecutiveInputCount = 0; // 重置计数
+  returnLastInputTime = 0; // 重置时间
+  returnSearchText.value = bufferedValue;
+  handleReturnScanSearch();
+};
+
+// 调度归还流程RFID缓冲区提交(延迟提交)
+const scheduleReturnRFIDBufferSubmit = () => {
+  if (!readRuleConfig.value.enableRFIDBuffer) return;
+  clearReturnRFIDInputTimer();
+  const delay = Math.max(readRuleConfig.value.rfidInputTimeout || 120, 30);
+  returnRfidInputTimer = setTimeout(() => {
+    submitReturnRFIDBuffer();
+  }, delay);
+};
+
+// 处理归还设备输入(用于同步 textarea 内容,仅在缓冲模式下使用)
+const handleReturnDeviceInput = () => {
+  // 如果缓冲区有内容,确保 textarea 显示与缓冲区一致
+  // 这主要用于处理退格键等操作后的同步
+  if (returnRfidInputBuffer.value && returnSearchText.value !== returnRfidInputBuffer.value) {
+    returnSearchText.value = returnRfidInputBuffer.value;
+  }
+  // 注意:正常输入时,不干预 textarea 的内容,让默认行为处理
+};
+
+// 检测归还流程是否是高速扫码输入(通过输入速度判断)
+// 返回值:{ isHighSpeed: boolean, isFirstInput: boolean, timeSinceLastInput: number }
+const checkReturnInputSpeed = () => {
+  const now = Date.now();
+  const timeSinceLastInput = returnLastInputTime > 0 ? now - returnLastInputTime : 0;
+  const isFirstInput = returnLastInputTime === 0;
+  
+  if (!isFirstInput) {
+    returnLastInputTime = now;
+  }
+  
+  return {
+    isFirstInput,
+    timeSinceLastInput,
+    isHighSpeed: timeSinceLastInput > 0 && timeSinceLastInput < readRuleConfig.value.minInputSpeed,
+    isNormalInput: timeSinceLastInput > 200
+  };
+};
+
+// 处理归还流程RFID键盘输入(高速扫码)
+const handleReturnRFIDKeydown = (event: KeyboardEvent) => {
+  // 如果未启用RFID缓冲,直接返回,不拦截
+  if (!readRuleConfig.value.enableRFIDBuffer) {
+    return;
+  }
+  
+  // 不拦截修饰键组合(如 Ctrl+C, Ctrl+V 等)
+  if (event.ctrlKey || event.metaKey || event.altKey) {
+    return;
+  }
+  
+  // 处理回车键
+  if (event.key === 'Enter') {
+    // 回车键由 @keydown.enter.prevent="handleReturnDeviceEnter" 处理
+    // 这里不处理,让 handleReturnDeviceEnter 统一处理
+    return;
+  }
+  
+  // 处理退格键
+  if (event.key === 'Backspace') {
+    // 如果有缓冲内容,处理缓冲
+    if (returnRfidInputBuffer.value) {
+      event.preventDefault();
+      returnRfidInputBuffer.value = returnRfidInputBuffer.value.slice(0, -1);
+      returnSearchText.value = returnRfidInputBuffer.value;
+    }
+    // 否则让默认行为处理
+    return;
+  }
+  
+  // 处理普通字符输入
+  if (event.key.length === 1) {
+    const inputInfo = checkReturnInputSpeed();
+    const { isFirstInput, isHighSpeed, isNormalInput, timeSinceLastInput } = inputInfo;
+    
+    // 如果是第一次输入,不拦截,让默认行为处理,只记录时间戳
+    if (isFirstInput) {
+      returnLastInputTime = Date.now();
+      // 不拦截,让字符正常输入到 textarea
+      return;
+    }
+    
+    // 如果检测到是正常输入(间隔 > 200ms),处理之前的缓冲内容
+    if (isNormalInput) {
+      // 如果之前有缓冲内容,先提交
+      if (returnRfidInputBuffer.value) {
+        submitReturnRFIDBuffer();
+      }
+      // 重置状态
+      returnConsecutiveInputCount = 0;
+      returnLastInputTime = Date.now();
+      // 不拦截,让字符正常输入到 textarea
+      return;
+    }
+    
+    // 如果检测到是高速输入(间隔 < 30ms),使用缓冲模式
+    if (isHighSpeed) {
+      event.preventDefault();
+      event.stopPropagation(); // 阻止事件冒泡,避免影响其他元素
+      
+      // 如果是第一次检测到高速输入(之前没有缓冲内容),需要将 textarea 中已有的内容也加入缓冲区
+      if (returnRfidInputBuffer.value === '' && returnSearchText.value) {
+        // textarea 中已经有内容(第一个字符已经通过默认行为输入了)
+        // 将整个内容作为缓冲区的初始值,然后追加当前字符
+        returnRfidInputBuffer.value = returnSearchText.value + event.key;
+      } else {
+        // 否则直接追加当前字符
+        returnRfidInputBuffer.value += event.key;
+      }
+      returnSearchText.value = returnRfidInputBuffer.value;
+      returnConsecutiveInputCount++;
+      scheduleReturnRFIDBufferSubmit();
+      return;
+    }
+    
+    // 如果输入间隔在 30-200ms 之间,可能是正常输入,不拦截
+    // 但如果之前有缓冲内容,说明高速输入已结束,先提交
+    if (returnRfidInputBuffer.value) {
+      submitReturnRFIDBuffer();
+      returnConsecutiveInputCount = 0;
+    }
+    returnLastInputTime = Date.now();
+    // 不拦截,让字符正常输入到 textarea
+  }
+};
+
+// 处理归还输入框失焦
+const handleReturnDeviceBlur = (event: FocusEvent) => {
+  // 如果焦点转移到其他输入元素(如表单输入框),不自动聚焦
+  const relatedTarget = event.relatedTarget as HTMLElement;
+  if (relatedTarget && (
+    relatedTarget.tagName === 'INPUT' || 
+    relatedTarget.tagName === 'TEXTAREA' ||
+    relatedTarget.closest('.el-input') ||
+    relatedTarget.closest('.el-textarea') ||
+    relatedTarget.closest('form')
+  )) {
+    // 如果有缓冲内容,先提交
+    if (returnRfidInputBuffer.value) {
+      submitReturnRFIDBuffer();
+    }
+    return;
+  }
+  
+  // 其他情况(如点击按钮等),延迟后自动聚焦
+  setTimeout(() => {
+    if (returnSearchInputRef.value && !loading.value) {
+      returnSearchInputRef.value.focus();
+    }
+  }, 10);
+};
+
+// 处理归还回车键
+const handleReturnDeviceEnter = (event: KeyboardEvent) => {
+  if (event.shiftKey) return;
+  event.preventDefault();
+  // 无论是否启用RFID缓冲,都调用 submitReturnRFIDBuffer
+  // submitReturnRFIDBuffer 内部会判断是否有缓冲内容,如果没有则直接使用 returnSearchText 搜索
+  submitReturnRFIDBuffer();
+};
+
+// 处理归还扫码搜索(支持批量,优化并发请求)
 const handleReturnScanSearch = async (event?: Event) => {
     // 阻止默认行为,防止表单提交导致页面刷新
     if (event) {
         event.preventDefault();
         event.stopPropagation();
     }
+    
+    // 如果启用了RFID缓冲,先提交缓冲区
+    if (readRuleConfig.value.enableRFIDBuffer && returnRfidInputBuffer.value) {
+      const bufferedValue = returnRfidInputBuffer.value;
+      returnRfidInputBuffer.value = '';
+      clearReturnRFIDInputTimer();
+      returnSearchText.value = bufferedValue;
+    }
+    
     if (!returnSearchText.value.trim()) return;
     
+    // 分割多个设备编号
+    const codes = splitDeviceCodes(returnSearchText.value);
+    if (codes.length === 0) return;
+    
+    // 去重处理,避免重复请求同一个设备编号
+    const uniqueCodes = Array.from(new Set(codes.map(code => code.trim()))).filter(Boolean);
+    if (uniqueCodes.length === 0) return;
+    
+    loading.value = true;
+    let successCount = 0;
+    let failCount = 0;
+    const errorMessages: string[] = [];
+    
     try {
-        const res = await deviceApi.GetList({ 
-            page: 1, 
-            limit: 1, 
-            code: returnSearchText.value.trim(),
-            status: 1 
-        });
-        
-        if (res.data && res.data.length > 0) {
-            const device = res.data[0];
-            const normalizedStatus = normalizeReturnStatus(device.return_status);
+      // 批量并发处理设备编号(使用 Promise.allSettled 确保所有请求都完成)
+      // 限制并发数量,避免同时发起过多请求
+      const batchSize = 10; // 每批处理10个
+      const batches: string[][] = [];
+      for (let i = 0; i < uniqueCodes.length; i += batchSize) {
+        batches.push(uniqueCodes.slice(i, i + batchSize));
+      }
+      
+      // 逐批处理,每批内部并发
+      for (const batch of batches) {
+        const promises = batch.map(async (code) => {
+          try {
+            const res = await deviceApi.GetList({ 
+              page: 1, 
+              limit: 1, 
+              code: code,
+              status: 1 
+            });
             
-            // 检查是否已存在
-            const existingDeviceIndex = returnDeviceList.value.findIndex(d => d.device_no === device.id);
-            if (existingDeviceIndex !== -1) {
+            if (res.data && res.data.length > 0) {
+              const device = res.data[0];
+              const normalizedStatus = normalizeReturnStatus(device.return_status);
+              
+              // 检查是否已存在
+              const existingDeviceIndex = returnDeviceList.value.findIndex(d => d.device_no === device.id);
+              if (existingDeviceIndex !== -1) {
                 // 如果设备已存在,更新其状态
                 returnDeviceList.value[existingDeviceIndex].return_status = normalizedStatus;
                 returnDeviceList.value[existingDeviceIndex].is_return = true;
                 returnDeviceList.value[existingDeviceIndex].return_time = dayjs().format('YYYY-MM-DD HH:mm:ss');
-                ElMessage.success(`设备 ${device.category_name} 状态已更新为已归还`);
+                return { success: true, code };
+              } else {
+                // 设备不存在于归还列表中
+                return { 
+                  success: false, 
+                  code, 
+                  message: `设备 ${device.code || device.category_name} 不在当前归还列表中,请先通过手动归还添加该设备` 
+                };
+              }
+            } else {
+              return { success: false, code, message: `未找到设备编号: ${code}` };
+            }
+          } catch (error) {
+            console.error(`处理设备编号 ${code} 失败:`, error);
+            return { success: false, code, message: `处理设备编号 ${code} 失败` };
+          }
+        });
+        
+        // 等待当前批次完成
+        const results = await Promise.allSettled(promises);
+        
+        // 统计结果
+        results.forEach((result, index) => {
+          if (result.status === 'fulfilled') {
+            const { success, message } = result.value;
+            if (success) {
+              successCount++;
             } else {
-                // 设备不存在于归还列表中,提示用户
-                ElMessage.warning(`设备 ${device.code || device.category_name} 不在当前归还列表中,请先通过手动归还添加该设备`);
+              failCount++;
+              if (message) {
+                errorMessages.push(message);
+              }
             }
-        } else {
-            ElMessage.warning('未找到对应的设备');
+          } else {
+            failCount++;
+            errorMessages.push(`处理设备编号 ${batch[index]} 时发生错误`);
+          }
+        });
+      }
+      
+      // 显示批量处理结果
+      if (uniqueCodes.length > 1) {
+        if (successCount > 0 && failCount === 0) {
+          ElMessage.success(`成功更新 ${successCount} 个设备状态为已归还`);
+        } else if (successCount > 0 && failCount > 0) {
+          ElMessage.warning(`成功更新 ${successCount} 个设备状态,失败 ${failCount} 个`);
+          // 只显示前3个错误信息,避免消息过多
+          if (errorMessages.length > 0) {
+            console.warn('批量处理错误详情:', errorMessages.slice(0, 3));
+          }
+        } else if (failCount > 0) {
+          ElMessage.error(`更新失败,共 ${failCount} 个设备编号`);
         }
+      } else if (successCount > 0) {
+        ElMessage.success('设备状态已更新为已归还');
+      } else if (failCount > 0 && errorMessages.length > 0) {
+        ElMessage.warning(errorMessages[0]);
+      }
     } catch (error) {
+        console.error('批量处理设备失败:', error);
         ElMessage.error('搜索设备失败');
     } finally {
         returnSearchText.value = ''; // 清空搜索框
+        loading.value = false;
         // 重新聚焦输入框,保持选中状态
         nextTick(() => {
-            returnSearchInputRef.value?.focus?.();
+            if (returnSearchInputRef.value) {
+              returnSearchInputRef.value.focus();
+              returnSearchInputRef.value.select();
+            }
         });
     }
 };
@@ -1648,6 +1992,11 @@ watch(
 			clearRFIDInputTimer();
 			consecutiveInputCount = 0;
 			lastInputTime = 0;
+			// 清理归还流程RFID缓冲状态
+			returnRfidInputBuffer.value = '';
+			clearReturnRFIDInputTimer();
+			returnConsecutiveInputCount = 0;
+			returnLastInputTime = 0;
 		}
 	}
 );
@@ -1879,6 +2228,11 @@ function onCancel() {
     clearRFIDInputTimer();
     consecutiveInputCount = 0;
     lastInputTime = 0;
+    // 清理归还流程RFID缓冲
+    returnRfidInputBuffer.value = '';
+    clearReturnRFIDInputTimer();
+    returnConsecutiveInputCount = 0;
+    returnLastInputTime = 0;
     // 关闭所有对话框
     showSelectDeviceDialog.value = false;
     showSettlementDialog.value = false;
@@ -2033,6 +2387,11 @@ onBeforeUnmount(() => {
   rfidInputBuffer.value = '';
   consecutiveInputCount = 0;
   lastInputTime = 0;
+  // 清理归还流程定时器和状态
+  clearReturnRFIDInputTimer();
+  returnRfidInputBuffer.value = '';
+  returnConsecutiveInputCount = 0;
+  returnLastInputTime = 0;
 });
 
 	/* formRef.value.validate((valid: boolean) => {