From 1ed040591afdcbe3c5df42ad5e02e2cfa56edd87 Mon Sep 17 00:00:00 2001
From: 云 <2163098428@qq.com>
Date: 星期二, 20 十月 2026 11:19:20 +0800
Subject: [PATCH] feat(mobile): 优化移动端质检记录界面功能

---
 src/views/mes/pro/batch/modules/form.vue |  122 ++++++++++++++++++++++++++++++++++++----
 1 files changed, 109 insertions(+), 13 deletions(-)

diff --git a/src/views/mes/pro/batch/modules/form.vue b/src/views/mes/pro/batch/modules/form.vue
index f27d9bb..f405c55 100644
--- a/src/views/mes/pro/batch/modules/form.vue
+++ b/src/views/mes/pro/batch/modules/form.vue
@@ -5,7 +5,7 @@
   import type { MesProBatchApi } from "#/api/mes/pro/batch";
   import type { SystemUserApi } from "#/api/system/user";
 
-  import { computed, nextTick, ref } from "vue";
+  import { computed, nextTick, reactive, ref } from "vue";
 
   import { useVbenModal } from "@vben/common-ui";
   import { DICT_TYPE } from "@vben/constants";
@@ -38,8 +38,77 @@
 
   const formType = ref<FormType>("create");
   const formData = ref<MesProBatchApi.Batch>();
-  let palletOptions: PalletOption[] = [];
-  let tonBagOptions: TonBagOption[] = [];
+  const BINDING_OPTION_PAGE_SIZE = 50;
+  const BINDING_SCROLL_THRESHOLD = 32;
+  let palletOptionSource: PalletOption[] = [];
+  let tonBagOptionSource: TonBagOption[] = [];
+  const palletOptions = reactive<PalletOption[]>([]);
+  const tonBagOptions = reactive<TonBagOption[]>([]);
+  let palletKeyword = "";
+  let tonBagKeyword = "";
+
+  function filterBindingOptions<T extends PalletOption>(source: T[], keyword: string): T[] {
+    const normalized = keyword.trim().toLowerCase();
+    if (!normalized) return source;
+    return source.filter((option) => option.label.toLowerCase().includes(normalized));
+  }
+
+  function resetBindingOptions<T extends PalletOption>(
+    target: T[],
+    source: T[],
+    keyword = ""
+  ) {
+    const filtered = filterBindingOptions(source, keyword);
+    target.splice(0, target.length, ...filtered.slice(0, BINDING_OPTION_PAGE_SIZE));
+  }
+
+  function appendBindingOptions<T extends PalletOption>(
+    target: T[],
+    source: T[],
+    keyword: string
+  ) {
+    const filtered = filterBindingOptions(source, keyword);
+    if (target.length >= filtered.length) return;
+    target.push(...filtered.slice(target.length, target.length + BINDING_OPTION_PAGE_SIZE));
+  }
+
+  function isPopupNearBottom(event: Event) {
+    const element = event.target as HTMLElement;
+    return element.scrollHeight - element.scrollTop - element.clientHeight <= BINDING_SCROLL_THRESHOLD;
+  }
+
+  function handlePalletSearch(keyword: string) {
+    palletKeyword = keyword;
+    resetBindingOptions(palletOptions, palletOptionSource, keyword);
+  }
+
+  function handleTonBagSearch(keyword: string) {
+    tonBagKeyword = keyword;
+    resetBindingOptions(tonBagOptions, tonBagOptionSource, keyword);
+  }
+
+  function handlePalletPopupScroll(event: Event) {
+    if (isPopupNearBottom(event)) {
+      appendBindingOptions(palletOptions, palletOptionSource, palletKeyword);
+    }
+  }
+
+  function handleTonBagPopupScroll(event: Event) {
+    if (isPopupNearBottom(event)) {
+      appendBindingOptions(tonBagOptions, tonBagOptionSource, tonBagKeyword);
+    }
+  }
+
+  const palletHandlers = {
+    onChange: handlePalletChange,
+    onPopupScroll: handlePalletPopupScroll,
+    onSearch: handlePalletSearch,
+  };
+  const tonBagHandlers = {
+    onChange: handleTonBagChange,
+    onPopupScroll: handleTonBagPopupScroll,
+    onSearch: handleTonBagSearch,
+  };
   async function handlePalletChange(ids: number[] = []) {
     const values = await formApi.getValues();
     if (ids.length && (values.tonBagIds?.length || formData.value?.bindingMode === 'tonBag')) {
@@ -47,7 +116,7 @@
       await formApi.setFieldValue('palletIds', []);
       return;
     }
-    const selected = palletOptions.filter(option => ids.includes(option.value));
+    const selected = palletOptionSource.filter(option => ids.includes(option.value));
     const source = formData.value?.itemId ? formData.value : selected[0];
     if (selected.some(option => !option.itemId || (source?.itemId && option.itemId !== source.itemId))) {
       message.warning('鐢熶骇鎵规鍙兘缁戝畾鐩稿悓鍝佺鐨勬墭鐩�');
@@ -65,7 +134,7 @@
       await formApi.setFieldValue('tonBagIds', []);
       return;
     }
-    const selected = tonBagOptions.filter(option => ids.includes(option.value));
+    const selected = tonBagOptionSource.filter(option => ids.includes(option.value));
     const source = formData.value?.itemId ? formData.value : selected[0];
     if (selected.some(option => option.itemId !== source?.itemId)) {
       message.warning('鐢熶骇鎵规鍙兘缁戝畾鐩稿悓鍝佺鐨勫惃琚�');
@@ -129,8 +198,9 @@
   let workerRowSeq = 0;
 
   /** 娣诲姞浜哄憳琛� */
-  function handleAddWorker() {
-    workerGridApi.grid.insertAt({ _rowKey: -(++workerRowSeq) }, -1);
+  async function handleAddWorker() {
+    await waitWorkerGridReady();
+    await workerGridApi.grid.insertAt({ _rowKey: -(++workerRowSeq) }, -1);
   }
 
   /** 鍒犻櫎浜哄憳琛� */
@@ -250,22 +320,47 @@
       const data = modalApi.getData<{ formType: FormType; id?: number }>();
       formType.value = data.formType;
       // 鏂板/琛ュ綍/缂栬緫鎬佸姞杞芥湭缁戝畾鎵规鐨勬墭鐩橈紝渚涖�岀粦瀹氭墭鐩樸�嶅閫変笅鎷変娇鐢�
-      palletOptions = [];
-      tonBagOptions = [];
+      palletOptionSource = [];
+      tonBagOptionSource = [];
+      palletOptions.splice(0);
+      tonBagOptions.splice(0);
+      palletKeyword = "";
+      tonBagKeyword = "";
+      // 鍏堟寕杞藉熀纭�琛ㄥ崟锛屽�欓�夋墭鐩�/鍚ㄨ鍦ㄥ悗鍙板姞杞斤紝閬垮厤鍙樉绀轰汉鍛橀厤缃殑绌虹獥鏈�
+      formApi.setState({
+        schema: useFormSchema(
+          formType.value,
+          palletOptions,
+          palletHandlers,
+          tonBagOptions,
+          tonBagHandlers
+        ),
+      });
       if (formType.value !== "detail") {
         const [pallets, tonBags] = await Promise.all([getUnboundPalletList(), getUnboundTonBags()]);
-        palletOptions = pallets.map((pallet) => ({
+        palletOptionSource = pallets.map((pallet) => ({
           label: `${pallet.tempCode ?? `鎵樼洏${pallet.id}`} 路 ${pallet.itemName || "寰呭畬鍠勫搧绉�"}锛堝凡瑁� ${pallet.bagCount ?? 0} 琚嬶級`,
           value: pallet.id as number,
           itemId: pallet.itemId, itemName: pallet.itemName, itemCode: pallet.itemCode,
         }));
-        tonBagOptions = tonBags.map((bag) => ({
+        tonBagOptionSource = tonBags.map((bag) => ({
           label: `${bag.code ?? `鍚ㄨ${bag.id}`} 路 ${bag.itemName || '寰呭畬鍠勫搧绉�'}`,
           value: bag.id as number,
           itemId: bag.itemId, itemName: bag.itemName, itemCode: bag.itemCode,
         }));
+        resetBindingOptions(palletOptions, palletOptionSource);
+        resetBindingOptions(tonBagOptions, tonBagOptionSource);
       }
-      formApi.setState({ schema: useFormSchema(formType.value, palletOptions, handlePalletChange, tonBagOptions, handleTonBagChange) });
+      // 閲嶆柊鍚屾涓�娆� Schema锛屼娇渚濊禆瀛楁涓殑鍔ㄦ�� options 绔嬪嵆鎷垮埌棣栨壒鍊欓�夐」
+      formApi.setState({
+        schema: useFormSchema(
+          formType.value,
+          palletOptions,
+          palletHandlers,
+          tonBagOptions,
+          tonBagHandlers
+        ),
+      });
       if (formType.value !== "detail") {
         // 娓呯┖涓婃鎵撳紑鏃跺嬀閫夌殑鎵樼洏锛岄伩鍏嶆畫鐣欏�艰瑙﹀彂銆屾壒娆¤繘鍏ョ敓浜т腑銆�
         await formApi.setFieldValue("palletIds", undefined);
@@ -282,7 +377,7 @@
         try {
           formData.value = await getBatch(data.id);
           const existingBinding = formData.value.bindingMode;
-          formApi.setState({ schema: useFormSchema(formType.value, palletOptions, handlePalletChange, tonBagOptions, handleTonBagChange, existingBinding) });
+          formApi.setState({ schema: useFormSchema(formType.value, palletOptions, palletHandlers, tonBagOptions, tonBagHandlers, existingBinding) });
           await formApi.setValues(formData.value);
           const workers = (formData.value.workers ?? []).map(
             (worker, index) => ({ ...worker, _rowKey: worker.id ?? index })
@@ -295,6 +390,7 @@
       } else {
         await waitWorkerGridReady();
         await workerGridApi.grid.loadData([]);
+        await handleAddWorker();
       }
     },
   });

--
Gitblit v1.9.3