From 5d321660a2f1a4b8756f816283e96481a8c934e4 Mon Sep 17 00:00:00 2001
From: 云 <2163098428@qq.com>
Date: 星期三, 28 十月 2026 14:26:30 +0800
Subject: [PATCH] feat(app): 更新应用名称并优化批次绑定功能

---
 src/api/mes/pro/pallet/index.ts                                                     |   13 
 src/packages/effects/common-ui/src/components/captcha/verification/index.vue        |   26 +
 src/views/_core/authentication/login.vue                                            |   24 +
 .env                                                                                |    2 
 src/layouts/auth.vue                                                                |    4 
 src/api/mes/pro/bagCode/index.ts                                                    |   13 
 company.config.ts                                                                   |    2 
 src/views/mes/pro/batch/data.ts                                                     |   74 ++++-
 public/images/tahe-logo.png                                                         |    0 
 src/packages/effects/common-ui/src/components/captcha/verification/verify-slide.vue |    5 
 src/views/mes/pro/batch/modules/form.vue                                            |  274 +++++++++++++++++-----
 src/packages/effects/layouts/src/authentication/authentication.vue                  |  266 ---------------------
 12 files changed, 340 insertions(+), 363 deletions(-)

diff --git a/.env b/.env
index bba56ab..cb6d2a6 100644
--- a/.env
+++ b/.env
@@ -1,5 +1,5 @@
 # 搴旂敤鏍囬
-VITE_APP_TITLE=宸ヤ笟AI鏅洪�犲钩鍙�
+VITE_APP_TITLE=濉旀渤绉嶄笟鍔犲伐閿�鍞緵搴旈摼鏁板瓧鍖栫鐞嗗钩鍙�
 
 # 搴旂敤鍛藉悕绌洪棿锛岀敤浜庣紦瀛樸�乻tore绛夊姛鑳界殑鍓嶇紑锛岀‘淇濋殧绂�
 VITE_APP_NAMESPACE=yudao-vben-antd
diff --git a/company.config.ts b/company.config.ts
index 92c4893..72e8ae9 100644
--- a/company.config.ts
+++ b/company.config.ts
@@ -18,7 +18,7 @@
  */
 export const companies: Record<string, CompanyConfig> = {
   TEST: {
-    name: '鏂扮枂濉旀渤绉嶄笟',
+    name: '濉旀渤绉嶄笟鍔犲伐閿�鍞緵搴旈摼鏁板瓧鍖栫鐞嗗钩鍙�',
     logo: '/logos/TEST.png',
     favicon: '/logos/TEST.ico',
     apiUrl: 'http://1.95.78.124:9008/admin-api',
diff --git a/public/images/tahe-logo.png b/public/images/tahe-logo.png
new file mode 100644
index 0000000..994f5e3
--- /dev/null
+++ b/public/images/tahe-logo.png
Binary files differ
diff --git a/src/api/mes/pro/bagCode/index.ts b/src/api/mes/pro/bagCode/index.ts
index 35c1cb1..54cb12d 100644
--- a/src/api/mes/pro/bagCode/index.ts
+++ b/src/api/mes/pro/bagCode/index.ts
@@ -263,9 +263,16 @@
   );
 }
 
-/** 鍙粦瀹氭壒娆$殑鍚ㄨ锛堟棤鎵樼洏涓旀湭缁戝畾鎵规锛� */
-export function getUnboundTonBags() {
-  return requestClient.get<MesProBagCodeApi.BagCode[]>('/mes/pro/bag-code/unbound-ton-bags');
+/** 鍒嗛〉鏌ヨ鍙粦瀹氭壒娆$殑鍚ㄨ锛堟棤鎵樼洏涓旀湭缁戝畾鎵规锛屽搧绉嶈閲忓崟浣嶄负鍚級 */
+export function getUnboundTonBagPage(params: {
+  keyword?: string;
+  pageNo: number;
+  pageSize: number;
+}) {
+  return requestClient.get<PageResult<MesProBagCodeApi.BagCode>>(
+    '/mes/pro/bag-code/unbound-ton-bag-page',
+    { params },
+  );
 }
 
 /** 鎵归噺瀵煎嚭琚嬬爜 Excel锛堜氦浠樺嵃鍒凤級 */
diff --git a/src/api/mes/pro/pallet/index.ts b/src/api/mes/pro/pallet/index.ts
index f964b2f..12eab4d 100644
--- a/src/api/mes/pro/pallet/index.ts
+++ b/src/api/mes/pro/pallet/index.ts
@@ -137,10 +137,15 @@
   );
 }
 
-/** 鏌ヨ鏈粦瀹氭壒娆$殑涓存椂鎵樼洏鍒楄〃锛堜緵鎵规鏂板/琛ュ綍缁戝畾鎵樼洏涓嬫媺浣跨敤锛� */
-export function getUnboundPalletList() {
-  return requestClient.get<MesProPalletApi.Pallet[]>(
-    '/mes/pro/pallet/unbound-list',
+/** 鍒嗛〉鏌ヨ鏈粦瀹氭壒娆$殑涓存椂鎵樼洏锛堜緵鎵规鏂板/琛ュ綍缁戝畾鎵樼洏涓嬫媺婊氬姩鍔犺浇锛� */
+export function getUnboundPalletPage(params: {
+  keyword?: string;
+  pageNo: number;
+  pageSize: number;
+}) {
+  return requestClient.get<PageResult<MesProPalletApi.Pallet>>(
+    '/mes/pro/pallet/unbound-page',
+    { params },
   );
 }
 
diff --git a/src/layouts/auth.vue b/src/layouts/auth.vue
index cb63894..ba3a783 100644
--- a/src/layouts/auth.vue
+++ b/src/layouts/auth.vue
@@ -9,7 +9,7 @@
 
 declare const __APP_LOGO__: string;
 
-const appName = computed(() => '绉嶆涓氭暟瀛楀寲骞冲彴');
+const appName = computed(() => '濉旀渤绉嶄笟鍔犲伐閿�鍞緵搴旈摼鏁板瓧鍖栫鐞嗗钩鍙�');
 const logo = computed(() => __APP_LOGO__ || preferences.logo.source);
 const logoDark = computed(() => preferences.logo.sourceDark);
 </script>
@@ -25,7 +25,7 @@
     :logo="logo"
     :logo-dark="logoDark"
     page-description="鏁板瓧璧嬭兘鍐滀笟 路 绉戞妧寮曢鏈潵"
-    page-title="绉嶆涓氭暟瀛楀寲骞冲彴"
+    page-title="濉旀渤绉嶄笟鍔犲伐閿�鍞緵搴旈摼鏁板瓧鍖栫鐞嗗钩鍙�"
   >
     <!-- 鑷畾涔夊伐鍏锋爮 -->
     <!-- <template #toolbar></template> -->
diff --git a/src/packages/effects/common-ui/src/components/captcha/verification/index.vue b/src/packages/effects/common-ui/src/components/captcha/verification/index.vue
index be6a098..8ae2544 100644
--- a/src/packages/effects/common-ui/src/components/captcha/verification/index.vue
+++ b/src/packages/effects/common-ui/src/components/captcha/verification/index.vue
@@ -5,7 +5,15 @@
  */
 import type { VerificationProps } from './typing';
 
-import { defineAsyncComponent, markRaw, ref, toRefs, watchEffect } from 'vue';
+import {
+  computed,
+  defineAsyncComponent,
+  markRaw,
+  nextTick,
+  ref,
+  toRefs,
+  watchEffect,
+} from 'vue';
 
 import { IconifyIcon } from '../../../../../../icons/src';
 
@@ -58,8 +66,20 @@
 };
 
 const show = () => {
-  if (mode.value === 'pop') showBox.value = true;
+  if (mode.value === 'pop') {
+    showBox.value = true;
+    // 姣忔鎵撳紑鎸夊綋鍓嶈鍙i噸鏂拌绠楀昂瀵革紝閫傞厤绉诲姩绔�
+    nextTick(() => instance.value?.init?.());
+  }
 };
+
+/** 寮圭獥鏈�澶у搴︼紝閬垮厤绐勫睆婧㈠嚭 */
+const boxMaxWidth = computed(() => {
+  const width = Number.parseInt(String(props.imgSize.width));
+  const limit =
+    typeof window === 'undefined' ? 420 : window.innerWidth - 24;
+  return `${Math.min(width + 20, limit)}px`;
+});
 
 const onError = (proxy: any) => {
   emit('onError', proxy);
@@ -109,7 +129,7 @@
   <div v-show="showBox">
     <div
       :class="mode === 'pop' ? 'verifybox' : ''"
-      :style="{ 'max-width': `${parseInt(imgSize.width) + 20}px` }"
+      :style="{ 'max-width': boxMaxWidth }"
     >
       <div v-if="mode === 'pop'" class="verifybox-top">
         {{ $t('ui.captcha.title') }}
diff --git a/src/packages/effects/common-ui/src/components/captcha/verification/verify-slide.vue b/src/packages/effects/common-ui/src/components/captcha/verification/verify-slide.vue
index 2dcbdf4..b1a06a1 100644
--- a/src/packages/effects/common-ui/src/components/captcha/verification/verify-slide.vue
+++ b/src/packages/effects/common-ui/src/components/captcha/verification/verify-slide.vue
@@ -108,7 +108,8 @@
   window.removeEventListener('touchend', end);
   window.removeEventListener('mouseup', end);
 
-  window.addEventListener('touchmove', move);
+  // passive: false 浠ヤ究鎷栧姩婊戝潡鏃堕樆姝㈤〉闈㈡粴鍔�
+  window.addEventListener('touchmove', move, { passive: false });
   window.addEventListener('mousemove', move);
 
   // 榧犳爣鏉惧紑
@@ -144,6 +145,8 @@
 // 榧犳爣绉诲姩
 function move(e: MouseEvent | TouchEvent) {
   if (status.value && isEnd.value === false) {
+    // 绉诲姩绔嫋鍔ㄦ椂闃绘椤甸潰璺熼殢婊氬姩
+    if (e.cancelable) e.preventDefault();
     const x =
       ((e as TouchEvent).touches
         ? (e as TouchEvent).touches[0]?.pageX
diff --git a/src/packages/effects/layouts/src/authentication/authentication.vue b/src/packages/effects/layouts/src/authentication/authentication.vue
index bacba87..ae5fbea 100644
--- a/src/packages/effects/layouts/src/authentication/authentication.vue
+++ b/src/packages/effects/layouts/src/authentication/authentication.vue
@@ -106,27 +106,16 @@
       <div class="agri-promo-layer absolute inset-0 size-full overflow-hidden">
         <div
           :key="authPanelLeft ? 'left' : authPanelRight ? 'right' : 'center'"
-          class="agri-promo relative flex h-full flex-col justify-center px-8 text-left"
+          class="agri-promo relative flex h-full flex-col items-end justify-start px-10 pt-16 text-left"
         >
           <!-- 鍝佺墝鍖� -->
           <div class="agri-brand">
             <div class="flex items-center gap-4">
-              <svg viewBox="0 0 64 64" class="size-14 shrink-0" aria-hidden="true">
-                <circle
-                  cx="32" cy="32" r="25" fill="none" stroke="#6ee7b7" stroke-width="2.5"
-                  stroke-linecap="round" stroke-dasharray="118 40" transform="rotate(-30 32 32)"
-                />
-                <circle
-                  cx="32" cy="32" r="25" fill="none" stroke="#a7f3d0" stroke-width="2.5"
-                  stroke-linecap="round" stroke-dasharray="26 132" transform="rotate(115 32 32)"
-                />
-                <circle cx="53" cy="17" r="3" fill="#6ee7b7" />
-                <circle cx="9" cy="41" r="2.4" fill="#a7f3d0" />
-                <path d="M32 45c0-8 0-12 0-16" stroke="#a7f3d0" stroke-width="2.4" stroke-linecap="round" fill="none" />
-                <path d="M32 34C24 32 19.5 26 19.5 19.5 27.5 21.5 32 26 32 34Z" fill="#34d399" />
-                <path d="M32 30c6.5-1.5 10.5-6.5 10.5-12C36 20 32 24 32 30Z" fill="#6ee7b7" />
-                <path d="M20 47q12-6 24 0" stroke="#a7f3d0" stroke-width="2.4" stroke-linecap="round" fill="none" />
-              </svg>
+              <img
+                src="/images/tahe-logo.png"
+                alt="濉旀渤绉嶄笟"
+                class="h-16 w-auto shrink-0 rounded-xl bg-white/95 p-1.5 shadow-lg"
+              />
               <div>
                 <div class="agri-brand-title text-3xl font-semibold tracking-[0.14em] xl:text-4xl">
                   {{ pageTitle }}
@@ -136,125 +125,13 @@
                 </div>
               </div>
             </div>
-            <div class="agri-brand-tag mt-6 flex items-center gap-4">
+            <div class="agri-brand-tag mt-6 flex items-center justify-end gap-4">
               <span class="agri-brand-tag-line h-px w-12"></span>
               <span class="text-base tracking-[0.22em]">{{ pageDescription }}</span>
               <span class="agri-brand-tag-line h-px w-12"></span>
             </div>
           </div>
 
-          <div class="mt-12 flex items-start gap-10">
-            <!-- 鏁版嵁鍗$墖鍒� -->
-            <div class="agri-stats flex w-60 shrink-0 flex-col gap-4" aria-label="骞冲彴杩愯姒傝">
-              <div class="agri-stat">
-                <span class="agri-stat-icon">
-                  <svg viewBox="0 0 24 24" class="size-5" fill="none" stroke="currentColor" stroke-width="1.9" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true">
-                    <path d="M12 20v-8" />
-                    <path d="M12 12C12 8 9 5 4.5 4.5 5 9 8 12 12 12Z" />
-                    <path d="M12 10c0-3.5 2.6-6 7-6.5-.4 4-3 6.5-7 6.5Z" />
-                    <path d="M5 20h14" />
-                  </svg>
-                </span>
-                <div>
-                  <span class="agri-stat-label">绉嶆闈㈢Н</span>
-                  <div class="agri-stat-num">12,580<i>浜�</i></div>
-                  <span class="agri-stat-trend agri-stat-up">杈冩槰鏃� 鈫� 2.35%</span>
-                </div>
-              </div>
-              <div class="agri-stat">
-                <span class="agri-stat-icon">
-                  <svg viewBox="0 0 24 24" class="size-5" fill="none" stroke="currentColor" stroke-width="1.9" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true">
-                    <rect x="6" y="6" width="12" height="12" rx="2" />
-                    <rect x="10" y="10" width="4" height="4" />
-                    <path d="M9 2v4M15 2v4M9 18v4M15 18v4M2 9h4M2 15h4M18 9h4M18 15h4" />
-                  </svg>
-                </span>
-                <div>
-                  <span class="agri-stat-label">鍦ㄧ嚎璁惧</span>
-                  <div class="agri-stat-num">1,286<i>鍙�</i></div>
-                  <span class="agri-stat-trend agri-stat-up">杈冩槰鏃� 鈫� 5.21%</span>
-                </div>
-              </div>
-              <div class="agri-stat">
-                <span class="agri-stat-icon">
-                  <svg viewBox="0 0 24 24" class="size-5" fill="none" stroke="currentColor" stroke-width="1.9" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true">
-                    <path d="M12 3s-6 6.6-6 11a6 6 0 0 0 12 0c0-4.4-6-11-6-11Z" />
-                    <path d="M9.5 14a2.5 2.5 0 0 0 2.5 2.5" />
-                  </svg>
-                </span>
-                <div>
-                  <span class="agri-stat-label">浠婃棩鐏屾簤</span>
-                  <div class="agri-stat-num">328<i>浜�</i></div>
-                  <span class="agri-stat-trend agri-stat-up">杈冩槰鏃� 鈫� 1.15%</span>
-                </div>
-              </div>
-              <div class="agri-stat">
-                <span class="agri-stat-icon agri-stat-icon-warn">
-                  <svg viewBox="0 0 24 24" class="size-5" fill="none" stroke="currentColor" stroke-width="1.9" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true">
-                    <path d="M18 9a6 6 0 1 0-12 0c0 5-2 6-2 6h16s-2-1-2-6" />
-                    <path d="M10.3 19a2 2 0 0 0 3.4 0" />
-                  </svg>
-                </span>
-                <div>
-                  <span class="agri-stat-label">AI 棰勮</span>
-                  <div class="agri-stat-num">6<i>鏉�</i></div>
-                  <span class="agri-stat-trend agri-stat-down">杈冩槰鏃� 鈫� 12.50%</span>
-                </div>
-              </div>
-            </div>
-
-            <!-- 鐩戞祴闈㈡澘鍒� -->
-            <div class="agri-monitors hidden w-72 shrink-0 flex-col gap-6 xl:flex">
-              <div class="agri-monitor">
-                <div class="agri-monitor-title">鍦熷¥澧掓儏鐩戞祴</div>
-                <div class="mt-3 flex items-baseline gap-2">
-                  <svg viewBox="0 0 24 24" class="size-5 self-center" aria-hidden="true">
-                    <path d="M12 3c0 0-6 6.6-6 11a6 6 0 0 0 12 0c0-4.4-6-11-6-11Z" fill="#7dd3fc" />
-                  </svg>
-                  <strong>68.5%</strong>
-                  <span>鍦熷¥婀垮害</span>
-                </div>
-                <svg viewBox="0 0 260 92" class="mt-3 w-full" aria-hidden="true">
-                  <defs>
-    <linearGradient id="agriSoilGrad" x1="0" y1="0" x2="0" y2="1">
-      <stop offset="0%" stop-color="rgba(110, 231, 183, 0.55)" />
-      <stop offset="100%" stop-color="rgba(110, 231, 183, 0.04)" />
-    </linearGradient>
-                  </defs>
-                  <g stroke="rgba(255, 255, 255, 0.14)" stroke-dasharray="3 4" stroke-width="1">
-                    <path d="M28 10h226" /><path d="M28 45h226" /><path d="M28 80h226" />
-                  </g>
-                  <g fill="rgba(255, 255, 255, 0.55)" font-size="8">
-                    <text x="2" y="13">100%</text><text x="6" y="48">50%</text><text x="6" y="83">0%</text>
-                  </g>
-                  <path
-                    d="M28 62 C48 58 60 68 76 60 C94 51 108 64 124 56 C142 47 158 54 174 42 C192 30 210 40 228 30 C240 24 248 27 254 22 L254 80 L28 80 Z"
-                    fill="url(#agriSoilGrad)"
-                  />
-                  <path
-                    d="M28 62 C48 58 60 68 76 60 C94 51 108 64 124 56 C142 47 158 54 174 42 C192 30 210 40 228 30 C240 24 248 27 254 22"
-                    fill="none" stroke="#6ee7b7" stroke-width="2" stroke-linecap="round"
-                  />
-                </svg>
-                <div class="agri-monitor-axis">
-                  <span>00:00</span><span>06:00</span><span>12:00</span><span>18:00</span><span>24:00</span>
-                </div>
-              </div>
-
-              <div class="agri-monitor agri-monitor-ai">
-                <div class="agri-monitor-title flex items-center gap-2">
-                  <svg viewBox="0 0 24 24" class="size-4.5" fill="none" stroke="#a7f3d0" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true">
-                    <path d="M12 3l1.9 5.1L19 10l-5.1 1.9L12 17l-1.9-5.1L5 10l5.1-1.9Z" />
-                    <path d="M19 15l.9 2.1L22 18l-2.1.9L19 21l-.9-2.1L16 18l2.1-.9Z" />
-                  </svg>
-                  AI 鏅鸿兘鍒嗘瀽
-                </div>
-                <p>
-                  褰撳墠浣滅墿闀垮娍鑹ソ锛屽湡澹ゅ鎯呴�傚疁锛屾湭鏉�3澶╂棤鏄庢樉闄嶉洦锛屽缓璁�傛椂鐏屾簤锛屼繚璇佷綔鐗╃ǔ浜ч珮浜с��
-                </p>
-              </div>
-            </div>
-          </div>
         </div>
 
       </div>
@@ -392,124 +269,6 @@
   margin-left: clamp(2rem, 6vw, 7rem);
   padding-top: 3rem;
   padding-bottom: 4.5rem;
-}
-
-.agri-brand svg {
-  filter: drop-shadow(0 6px 16px rgba(16, 185, 129, 0.35));
-}
-
-/* ---------- 鏁版嵁鍗$墖 ---------- */
-.agri-stat {
-  display: flex;
-  align-items: center;
-  gap: 0.85rem;
-  border: 1px solid rgba(167, 243, 208, 0.42);
-  border-radius: 1.1rem;
-  background: linear-gradient(135deg, rgba(8, 87, 65, 0.66), rgba(4, 57, 49, 0.3));
-  padding: 0.9rem 1rem;
-  box-shadow: 0 12px 28px rgba(0, 36, 28, 0.16);
-  transition: border-color 200ms ease, background 200ms ease;
-  color: rgba(236, 253, 245, 0.92);
-  backdrop-filter: blur(12px);
-}
-
-.agri-stat-icon {
-  display: flex;
-  align-items: center;
-  justify-content: center;
-  width: 2.6rem;
-  height: 2.6rem;
-  flex-shrink: 0;
-  border-radius: 9999px;
-  background: linear-gradient(135deg, #10b981, #047857);
-  color: #ecfdf5;
-  box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.22);
-}
-
-.agri-stat-icon-warn {
-  background: linear-gradient(135deg, #f59e0b, #b45309);
-}
-
-.agri-stat-label {
-  font-size: 0.75rem;
-  color: rgba(236, 253, 245, 0.75);
-}
-
-.agri-stat-num {
-  margin-top: 0.1rem;
-  font-size: 1.35rem;
-  font-weight: 700;
-  color: #fff;
-  line-height: 1.2;
-}
-
-.agri-stat-num i {
-  margin-left: 0.3rem;
-  font-size: 0.75rem;
-  font-style: normal;
-  font-weight: 400;
-  color: rgba(236, 253, 245, 0.8);
-}
-
-.agri-stat-trend {
-  display: block;
-  margin-top: 0.15rem;
-  font-size: 0.7rem;
-}
-
-.agri-stat-up { color: #6ee7b7; }
-.agri-stat-down { color: #fca5a5; }
-
-/* ---------- 鐩戞祴闈㈡澘 ---------- */
-.agri-monitor {
-  border: 1px solid rgba(125, 211, 252, 0.4);
-  border-radius: 1.1rem;
-  background: linear-gradient(160deg, rgba(8, 51, 68, 0.6), rgba(6, 78, 59, 0.32));
-  padding: 1rem 1.1rem;
-  color: rgba(236, 253, 245, 0.92);
-  backdrop-filter: blur(12px);
-  box-shadow: 0 0 24px rgba(56, 189, 248, 0.18), 0 14px 30px rgba(0, 36, 28, 0.18);
-}
-
-.agri-monitor-title {
-  font-size: 0.85rem;
-  font-weight: 600;
-  letter-spacing: 0.08em;
-  color: #bae6fd;
-}
-
-.agri-monitor strong {
-  font-size: 1.6rem;
-  font-weight: 700;
-  color: #fff;
-}
-
-.agri-monitor strong + span,
-.agri-monitor-title + div span {
-  font-size: 0.75rem;
-  color: rgba(236, 253, 245, 0.75);
-}
-
-.agri-monitor-axis {
-  display: flex;
-  justify-content: space-between;
-  margin-top: 0.35rem;
-  padding-left: 1.6rem;
-  font-size: 0.7rem;
-  color: rgba(255, 255, 255, 0.6);
-}
-
-.agri-monitor-ai {
-  margin-left: 2.5rem;
-  border-color: rgba(167, 243, 208, 0.4);
-  box-shadow: 0 0 24px rgba(52, 211, 153, 0.16), 0 14px 30px rgba(0, 36, 28, 0.18);
-}
-
-.agri-monitor-ai p {
-  margin: 0.6rem 0 0;
-  font-size: 0.78rem;
-  line-height: 1.7;
-  color: rgba(236, 253, 245, 0.85);
 }
 
 /* ---------- 鍙充晶鐧诲綍鍗$墖 ---------- */
@@ -665,17 +424,6 @@
     animation: agri-in-right 0.75s cubic-bezier(0.22, 0.61, 0.36, 1) both;
   }
 
-  .agri-stat,
-  .agri-monitor {
-    animation: agri-in-up 0.55s cubic-bezier(0.22, 0.61, 0.36, 1) both;
-  }
-
-  .agri-stat:nth-child(1) { animation-delay: 0.2s; }
-  .agri-stat:nth-child(2) { animation-delay: 0.28s; }
-  .agri-stat:nth-child(3) { animation-delay: 0.36s; }
-  .agri-stat:nth-child(4) { animation-delay: 0.44s; }
-  .agri-monitor:nth-child(1) { animation-delay: 0.3s; }
-  .agri-monitor:nth-child(2) { animation-delay: 0.4s; }
 }
 
 @keyframes agri-in-left {
diff --git a/src/views/_core/authentication/login.vue b/src/views/_core/authentication/login.vue
index 92c9711..80fd448 100644
--- a/src/views/_core/authentication/login.vue
+++ b/src/views/_core/authentication/login.vue
@@ -27,6 +27,15 @@
 
 const captchaType = 'blockPuzzle'; // 楠岃瘉鐮佺被鍨嬶細'blockPuzzle' | 'clickWord'
 
+/** 婊戝潡楠岃瘉鐮佸昂瀵革細绉诲姩绔寜瑙嗗彛瀹藉害鏀剁缉锛岄伩鍏嶈秴鍑哄睆骞曟棤娉曟嫋鍔� */
+const captchaImgSize = computed(() => {
+  const width =
+    terminalType.value === 'mobile'
+      ? Math.min(315, Math.max(260, window.innerWidth - 48))
+      : 400;
+  return { width: `${width}px`, height: `${Math.round(width / 2)}px` };
+});
+
 /** 澶勭悊鐧诲綍 */
 async function handleLogin(values: AuthApi.LoginParams) {
   if (captchaEnable) {
@@ -87,6 +96,14 @@
 
 <template>
   <div>
+    <div class="login-brand">
+      <img
+        src="/images/tahe-logo.png"
+        alt="濉旀渤绉嶄笟"
+        class="login-brand-logo"
+      />
+      <p class="login-brand-name">濉旀渤绉嶄笟鍔犲伐閿�鍞緵搴旈摼鏁板瓧鍖栫鐞嗗钩鍙�</p>
+    </div>
     <fieldset class="terminal-selector">
       <legend>閫夋嫨浣跨敤绔�</legend>
       <div class="terminal-options">
@@ -108,7 +125,7 @@
       :show-field-labels="terminalType === 'mobile'"
       :submit-button-text="terminalType === 'mobile' ? '鐧诲綍绉诲姩绔�' : '鐧诲綍 PC 绔�'"
       title="娆㈣繋鍥炴潵"
-      :sub-title="terminalType === 'mobile' ? '浣跨敤宸叉湁璐﹀彿鐧诲綍鐜板満浣滀笟' : '鐧诲綍绉嶆涓氭暟瀛楀寲骞冲彴锛屽紑鍚櫤鎱х妞�'"
+      :sub-title="terminalType === 'mobile' ? '浣跨敤宸叉湁璐﹀彿鐧诲綍鐜板満浣滀笟' : '鐧诲綍濉旀渤绉嶄笟鍔犲伐閿�鍞緵搴旈摼鏁板瓧鍖栫鐞嗗钩鍙�'"
       :show-code-login="false"
       :show-qrcode-login="false"
       :show-third-party-login="false"
@@ -124,7 +141,7 @@
       :captcha-type="captchaType"
       :check-captcha-api="checkCaptcha"
       :get-captcha-api="getCaptcha"
-      :img-size="{ width: '400px', height: '200px' }"
+      :img-size="captchaImgSize"
       mode="pop"
       @on-success="handleVerifySuccess"
     />
@@ -132,6 +149,9 @@
 </template>
 
 <style scoped>
+.login-brand { display: flex; flex-direction: column; align-items: center; gap: 8px; margin-bottom: 24px; }
+.login-brand-logo { height: 72px; width: auto; }
+.login-brand-name { margin: 0; text-align: center; font-size: 16px; font-weight: 600; letter-spacing: 0.02em; color: #0f172a; }
 .terminal-selector { border: 0; margin: 0 0 24px; padding: 0; }
 .login-error { padding:12px;color:#b91c1c;background:#fef2f2;border-radius:8px; }
 .terminal-selector legend { font-size: 16px; margin-bottom: 8px; }
diff --git a/src/views/mes/pro/batch/data.ts b/src/views/mes/pro/batch/data.ts
index f32b8f0..4be0fd3 100644
--- a/src/views/mes/pro/batch/data.ts
+++ b/src/views/mes/pro/batch/data.ts
@@ -16,20 +16,58 @@
 
 /** 鏈粦瀹氭墭鐩樹笅鎷夐�夐」 */
 export interface PalletOption {
-  label: string;
-  value: number;
+  disabled?: boolean;
+  itemCode?: string;
   itemId?: number;
   itemName?: string;
-  itemCode?: string;
+  label: string;
+  value: number;
 }
 
 export type TonBagOption = PalletOption;
 
-/** 鎵樼洏銆佸惃琚嬩笅鎷夌殑浜や簰浜嬩欢锛堟敮鎸佹悳绱笌婊氬姩鍒嗘鍔犺浇锛� */
+/** 缁戝畾绫诲瀷锛堟墭鐩�/鍚ㄨ浜掓枼锛岀紪杈戣ˉ褰曟椂鎸夊凡鏈夌粦瀹氶攣瀹氬叾涓竴鏂癸級 */
+export type BindingMode = 'pallet' | 'tonBag';
+
+/** 鎵樼洏銆佸惃琚嬩笅鎷夌殑浜や簰浜嬩欢锛堟敮鎸佽繙绋嬫悳绱笌婊氬姩鍒嗛〉鍔犺浇锛� */
 export interface BindingSelectHandlers {
   onChange?: (ids: number[]) => void;
   onPopupScroll?: (event: Event) => void;
   onSearch?: (keyword: string) => void;
+}
+
+/**
+ * 鍒锋柊鎵樼洏閫夐」绂佺敤鎬併��
+ *
+ * 涓嬫媺宸叉敼涓哄垎椤靛姞杞斤紝閫夐」鏁扮粍鏈韩灏辨槸娓叉煋鏁版嵁婧愶紝鍥犳绂佺敤鎬佺洿鎺ュ啓鍒伴�夐」瀵硅薄涓婏紝
+ * 姣忔鍔犺浇鏂颁竴椤垫垨琛ㄥ崟鍊煎彉鍖栨椂閲嶇畻锛岄伩鍏嶄緷璧栨満鍒堕噷鍋氭暟缁勬槧灏勫鑷存柊鍔犺浇鐨勬暟鎹鏃у揩鐓ц鐩栥��
+ */
+export function applyPalletOptionState(
+  options: PalletOption[],
+  values: Record<string, any>,
+  existingBinding?: BindingMode,
+) {
+  options.forEach((option) => {
+    option.disabled =
+      existingBinding === 'tonBag' ||
+      !!values.tonBagIds?.length ||
+      !option.itemId ||
+      (!!values.itemId && option.itemId !== values.itemId);
+  });
+}
+
+/** 鍒锋柊鍚ㄨ閫夐」绂佺敤鎬侊紝瑙勫垯涓� {@link applyPalletOptionState} 瀵圭О */
+export function applyTonBagOptionState(
+  options: TonBagOption[],
+  values: Record<string, any>,
+  existingBinding?: BindingMode,
+) {
+  options.forEach((option) => {
+    option.disabled =
+      existingBinding === 'pallet' ||
+      !!values.palletIds?.length ||
+      (!!values.itemId && option.itemId !== values.itemId);
+  });
 }
 
 /** 鏂板/淇敼鐨勮〃鍗� */
@@ -39,7 +77,7 @@
   palletHandlers: BindingSelectHandlers = {},
   tonBagOptions: TonBagOption[] = [],
   tonBagHandlers: BindingSelectHandlers = {},
-  existingBinding?: 'pallet' | 'tonBag',
+  existingBinding?: BindingMode,
 ): VbenFormSchema[] {
   const disabled = formType === 'detail';
   return [
@@ -180,12 +218,13 @@
       dependencies: {
         triggerFields: ['itemId', 'tonBagIds'],
         show: () => formType !== 'detail',
-        componentProps: (values) => ({
-          options: palletOptions.map(option => ({ ...option,
-            disabled: existingBinding === 'tonBag' || !!values.tonBagIds?.length || !option.itemId || (!!values.itemId && option.itemId !== values.itemId),
-          })),
-          disabled: disabled || existingBinding === 'tonBag' || !!values.tonBagIds?.length,
-        }),
+        componentProps: (values) => {
+          applyPalletOptionState(palletOptions, values, existingBinding);
+          return {
+            options: palletOptions,
+            disabled: disabled || existingBinding === 'tonBag' || !!values.tonBagIds?.length,
+          };
+        },
       },
       help: '鍙兘缁戝畾鐩稿悓鍝佺鐨勬墭鐩橈紝鍝佺淇℃伅鑷姩甯﹀叆锛涚己灏戝搧绉嶇殑鎵樼洏璇峰厛瑁呰銆傜粦瀹氬悗鎵规鐩存帴杩涘叆鐢熶骇涓細鎵樼洏鐢熸垚姝e紡鎵樼洏鐮侊紝鎵樼洏涓嬫湭褰曟壒娆$殑琚嬬爜鑷姩绾ц仈褰曞叆鏈壒娆★紙琚嬬爜鍝佺椤讳竴鑷达級锛涚紪杈戞椂浠呴渶鍕鹃�夋柊澧炴墭鐩橈紝宸茬粦瀹氱殑涓嶅彲瑙g粦',
     },
@@ -210,12 +249,13 @@
       dependencies: {
         triggerFields: ['itemId', 'palletIds'],
         show: () => formType !== 'detail',
-        componentProps: (values) => ({
-          options: tonBagOptions.map(option => ({ ...option,
-            disabled: existingBinding === 'pallet' || !!values.palletIds?.length || (!!values.itemId && option.itemId !== values.itemId),
-          })),
-          disabled: disabled || existingBinding === 'pallet' || !!values.palletIds?.length,
-        }),
+        componentProps: (values) => {
+          applyTonBagOptionState(tonBagOptions, values, existingBinding);
+          return {
+            options: tonBagOptions,
+            disabled: disabled || existingBinding === 'pallet' || !!values.palletIds?.length,
+          };
+        },
       },
       help: '浠呭彲缁戝畾璁¢噺鍗曚綅涓哄惃銆佹棤鎵樼洏涓旀湭褰曞叆鎵规鐨勮鐮侊紱涓庣粦瀹氭墭鐩樹簰鏂ャ�傜紪杈戞椂浠呴�夋嫨鏂板鍚ㄨ锛屽凡缁戝畾鐨勪笉鍙В缁�',
     },
diff --git a/src/views/mes/pro/batch/modules/form.vue b/src/views/mes/pro/batch/modules/form.vue
index f405c55..1ef766d 100644
--- a/src/views/mes/pro/batch/modules/form.vue
+++ b/src/views/mes/pro/batch/modules/form.vue
@@ -21,12 +21,14 @@
     getBatch,
     updateBatch,
   } from "#/api/mes/pro/batch";
-  import { getUnboundPalletList } from "#/api/mes/pro/pallet";
-  import { getUnboundTonBags } from "#/api/mes/pro/bagCode";
+  import { getUnboundPalletPage } from "#/api/mes/pro/pallet";
+  import { getUnboundTonBagPage } from "#/api/mes/pro/bagCode";
   import { $t } from "#/locales";
   import { UserSelect } from "#/views/system/user/components";
 
   import {
+    applyPalletOptionState,
+    applyTonBagOptionState,
     useFormSchema,
     useWorkerEditGridColumns,
     useWorkerReadGridColumns,
@@ -38,38 +40,177 @@
 
   const formType = ref<FormType>("create");
   const formData = ref<MesProBatchApi.Batch>();
-  const BINDING_OPTION_PAGE_SIZE = 50;
+  /** 缁戝畾涓嬫媺姣忔鍔犺浇鐨勬潯鏁� */
+  const BINDING_PAGE_SIZE = 50;
+  /** 璺濈涓嬫媺搴曢儴澶氬皯鍍忕礌鏃惰Е鍙戝姞杞戒笅涓�椤� */
   const BINDING_SCROLL_THRESHOLD = 32;
-  let palletOptionSource: PalletOption[] = [];
-  let tonBagOptionSource: TonBagOption[] = [];
+  /** 杈撳叆妗嗘悳绱㈤槻鎶栨椂闂达紙姣锛� */
+  const BINDING_SEARCH_DEBOUNCE = 300;
+
+  /**
+   * 缁戝畾涓嬫媺鐨勫垎椤靛姞杞界姸鎬併��
+   *
+   * 涓嬫媺閫夐」鏈韩灏辨槸娓叉煋鏁版嵁婧愶紙淇濇寔鏁扮粍寮曠敤涓嶅彉锛岀洿鎺� splice 鏇存柊锛夛紝
+   * 宸插姞杞界殑鍒嗛〉缁撴灉鏀惧湪 loaded 涓紝璺ㄩ〉閫変腑鐨勯�夐」鍗曠嫭璁板綍锛岄伩鍏嶆崲椤垫悳绱㈠悗鏍囩涓㈠け銆�
+   */
+  interface BindingLoader<T extends PalletOption> {
+    hasMore: boolean;
+    keyword: string;
+    loaded: T[];
+    loading: boolean;
+    pageNo: number;
+    seq: number;
+    timer?: ReturnType<typeof setTimeout>;
+  }
+
+  function createBindingLoader<T extends PalletOption>(): BindingLoader<T> {
+    return {
+      hasMore: true,
+      keyword: "",
+      loaded: [],
+      loading: false,
+      pageNo: 0,
+      seq: 0,
+    };
+  }
+
   const palletOptions = reactive<PalletOption[]>([]);
   const tonBagOptions = reactive<TonBagOption[]>([]);
-  let palletKeyword = "";
-  let tonBagKeyword = "";
+  const palletSelected = new Map<number, PalletOption>();
+  const tonBagSelected = new Map<number, TonBagOption>();
+  const palletLoader = createBindingLoader<PalletOption>();
+  const tonBagLoader = createBindingLoader<TonBagOption>();
 
-  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 renderBindingOptions<T extends PalletOption>(
+    target: T[],
+    loader: BindingLoader<T>,
+    selected: Map<number, T>
+  ) {
+    const merged = [...loader.loaded];
+    const loadedIds = new Set(loader.loaded.map((option) => option.value));
+    selected.forEach((option, id) => {
+      if (!loadedIds.has(id)) merged.push(option);
+    });
+    target.splice(0, target.length, ...merged);
   }
 
-  function resetBindingOptions<T extends PalletOption>(
+  /** 鍚屾閫変腑椤癸紙鎹㈤〉鎼滅储鍚庝粛闇�灞曠ず宸查�夋爣绛撅級 */
+  function syncBindingSelection<T extends PalletOption>(
     target: T[],
-    source: T[],
-    keyword = ""
+    loader: BindingLoader<T>,
+    selected: Map<number, T>,
+    ids: number[]
   ) {
-    const filtered = filterBindingOptions(source, keyword);
-    target.splice(0, target.length, ...filtered.slice(0, BINDING_OPTION_PAGE_SIZE));
+    const previous = new Map(selected);
+    selected.clear();
+    ids.forEach((id) => {
+      const option = previous.get(id)
+        ?? loader.loaded.find((item) => item.value === id);
+      if (option) selected.set(id, option);
+    });
+    renderBindingOptions(target, loader, selected);
   }
 
-  function appendBindingOptions<T extends PalletOption>(
+  /** 閫夐」绂佺敤鎬佷緷璧栧綋鍓嶈〃鍗曞�硷紝姣忔鍔犺浇鏂颁竴椤靛悗閲嶆柊璁$畻 */
+  async function refreshBindingOptionState() {
+    const values = await formApi.getValues();
+    const existingBinding = formData.value?.bindingMode;
+    applyPalletOptionState(palletOptions, values, existingBinding);
+    applyTonBagOptionState(tonBagOptions, values, existingBinding);
+  }
+
+  /** 鎷夊彇涓�椤电粦瀹氬�欓�夐」锛況eset=true 琛ㄧず浠庣涓�椤甸噸鏂板紑濮嬶紙棣栨鎵撳紑銆佹悳绱級 */
+  async function loadBindingPage<T extends PalletOption>(
+    loader: BindingLoader<T>,
     target: T[],
-    source: T[],
-    keyword: string
+    selected: Map<number, T>,
+    fetchPage: (params: {
+      keyword?: string;
+      pageNo: number;
+      pageSize: number;
+    }) => Promise<{ list: T[]; total: number }>,
+    reset: boolean
   ) {
-    const filtered = filterBindingOptions(source, keyword);
-    if (target.length >= filtered.length) return;
-    target.push(...filtered.slice(target.length, target.length + BINDING_OPTION_PAGE_SIZE));
+    if (!reset && (loader.loading || !loader.hasMore)) return;
+    const seq = ++loader.seq;
+    loader.loading = true;
+    try {
+      const pageNo = reset ? 1 : loader.pageNo + 1;
+      const page = await fetchPage({
+        keyword: loader.keyword || undefined,
+        pageNo,
+        pageSize: BINDING_PAGE_SIZE,
+      });
+      // 宸茶鏇存柊鐨勬悳绱㈡垨骞跺彂璇锋眰瑕嗙洊锛屼涪寮冩湰娆$粨鏋�
+      if (seq !== loader.seq) return;
+      loader.loaded = reset ? page.list : [...loader.loaded, ...page.list];
+      loader.pageNo = pageNo;
+      loader.hasMore = loader.loaded.length < page.total;
+      renderBindingOptions(target, loader, selected);
+      await refreshBindingOptionState();
+    } finally {
+      if (seq === loader.seq) loader.loading = false;
+    }
+  }
+
+  function fetchPalletPage(params: {
+    keyword?: string;
+    pageNo: number;
+    pageSize: number;
+  }) {
+    return getUnboundPalletPage(params).then((page) => ({
+      list: page.list.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,
+      })),
+      total: page.total,
+    }));
+  }
+
+  function fetchTonBagPage(params: {
+    keyword?: string;
+    pageNo: number;
+    pageSize: number;
+  }) {
+    return getUnboundTonBagPage(params).then((page) => ({
+      list: page.list.map((bag) => ({
+        label: `${bag.code ?? `鍚ㄨ${bag.id}`} 路 ${bag.itemName || "寰呭畬鍠勫搧绉�"}`,
+        value: bag.id as number,
+        itemId: bag.itemId,
+        itemName: bag.itemName,
+        itemCode: bag.itemCode,
+      })),
+      total: page.total,
+    }));
+  }
+
+  function loadPalletPage(reset: boolean) {
+    return loadBindingPage(palletLoader, palletOptions, palletSelected, fetchPalletPage, reset);
+  }
+
+  function loadTonBagPage(reset: boolean) {
+    return loadBindingPage(tonBagLoader, tonBagOptions, tonBagSelected, fetchTonBagPage, reset);
+  }
+
+  /** 閲嶇疆涓嬫媺鍒嗛〉鐘舵�侊紙姣忔鎵撳紑寮圭獥璋冪敤锛夛紝鍚屾椂璁╁湪閫旇姹傜殑缁撴灉澶辨晥 */
+  function resetBindingLoader<T extends PalletOption>(
+    loader: BindingLoader<T>,
+    target: T[],
+    selected: Map<number, T>
+  ) {
+    clearTimeout(loader.timer);
+    loader.seq += 1;
+    loader.hasMore = true;
+    loader.keyword = "";
+    loader.loaded = [];
+    loader.loading = false;
+    loader.pageNo = 0;
+    target.splice(0, target.length);
+    selected.clear();
   }
 
   function isPopupNearBottom(event: Event) {
@@ -77,26 +218,30 @@
     return element.scrollHeight - element.scrollTop - element.clientHeight <= BINDING_SCROLL_THRESHOLD;
   }
 
+  function scheduleBindingSearch<T extends PalletOption>(
+    loader: BindingLoader<T>,
+    keyword: string,
+    reload: (reset: boolean) => Promise<void>
+  ) {
+    loader.keyword = keyword.trim();
+    clearTimeout(loader.timer);
+    loader.timer = setTimeout(() => void reload(true), BINDING_SEARCH_DEBOUNCE);
+  }
+
   function handlePalletSearch(keyword: string) {
-    palletKeyword = keyword;
-    resetBindingOptions(palletOptions, palletOptionSource, keyword);
+    scheduleBindingSearch(palletLoader, keyword, loadPalletPage);
   }
 
   function handleTonBagSearch(keyword: string) {
-    tonBagKeyword = keyword;
-    resetBindingOptions(tonBagOptions, tonBagOptionSource, keyword);
+    scheduleBindingSearch(tonBagLoader, keyword, loadTonBagPage);
   }
 
   function handlePalletPopupScroll(event: Event) {
-    if (isPopupNearBottom(event)) {
-      appendBindingOptions(palletOptions, palletOptionSource, palletKeyword);
-    }
+    if (isPopupNearBottom(event)) void loadPalletPage(false);
   }
 
   function handleTonBagPopupScroll(event: Event) {
-    if (isPopupNearBottom(event)) {
-      appendBindingOptions(tonBagOptions, tonBagOptionSource, tonBagKeyword);
-    }
+    if (isPopupNearBottom(event)) void loadTonBagPage(false);
   }
 
   const palletHandlers = {
@@ -109,19 +254,27 @@
     onPopupScroll: handleTonBagPopupScroll,
     onSearch: handleTonBagSearch,
   };
+
   async function handlePalletChange(ids: number[] = []) {
     const values = await formApi.getValues();
     if (ids.length && (values.tonBagIds?.length || formData.value?.bindingMode === 'tonBag')) {
       message.warning('缁戝畾鎵樼洏鍜岀粦瀹氬惃琚嬪彧鑳介�夋嫨涓�绉�');
       await formApi.setFieldValue('palletIds', []);
+      syncBindingSelection(palletOptions, palletLoader, palletSelected, []);
       return;
     }
-    const selected = palletOptionSource.filter(option => ids.includes(option.value));
+    const selected = ids
+      .map((id) => palletSelected.get(id) ?? palletLoader.loaded.find((option) => option.value === id))
+      .filter((option): option is PalletOption => !!option);
     const source = formData.value?.itemId ? formData.value : selected[0];
+    let finalIds = ids;
     if (selected.some(option => !option.itemId || (source?.itemId && option.itemId !== source.itemId))) {
       message.warning('鐢熶骇鎵规鍙兘缁戝畾鐩稿悓鍝佺鐨勬墭鐩�');
-      await formApi.setFieldValue('palletIds', selected.filter(option => option.itemId === source?.itemId).map(option => option.value));
+      finalIds = selected.filter(option => option.itemId === source?.itemId).map(option => option.value);
+      await formApi.setFieldValue('palletIds', finalIds);
     }
+    syncBindingSelection(palletOptions, palletLoader, palletSelected, finalIds);
+    await refreshBindingOptionState();
     await formApi.setFieldValue('itemId', source?.itemId);
     await formApi.setFieldValue('itemName', source?.itemName);
     await formApi.setFieldValue('itemCode', source?.itemCode);
@@ -132,14 +285,21 @@
     if (ids.length && (values.palletIds?.length || formData.value?.bindingMode === 'pallet')) {
       message.warning('缁戝畾鎵樼洏鍜岀粦瀹氬惃琚嬪彧鑳介�夋嫨涓�绉�');
       await formApi.setFieldValue('tonBagIds', []);
+      syncBindingSelection(tonBagOptions, tonBagLoader, tonBagSelected, []);
       return;
     }
-    const selected = tonBagOptionSource.filter(option => ids.includes(option.value));
+    const selected = ids
+      .map((id) => tonBagSelected.get(id) ?? tonBagLoader.loaded.find((option) => option.value === id))
+      .filter((option): option is TonBagOption => !!option);
     const source = formData.value?.itemId ? formData.value : selected[0];
+    let finalIds = ids;
     if (selected.some(option => option.itemId !== source?.itemId)) {
       message.warning('鐢熶骇鎵规鍙兘缁戝畾鐩稿悓鍝佺鐨勫惃琚�');
-      await formApi.setFieldValue('tonBagIds', selected.filter(option => option.itemId === source?.itemId).map(option => option.value));
+      finalIds = selected.filter(option => option.itemId === source?.itemId).map(option => option.value);
+      await formApi.setFieldValue('tonBagIds', finalIds);
     }
+    syncBindingSelection(tonBagOptions, tonBagLoader, tonBagSelected, finalIds);
+    await refreshBindingOptionState();
     await formApi.setFieldValue('itemId', source?.itemId);
     await formApi.setFieldValue('itemName', source?.itemName);
     await formApi.setFieldValue('itemCode', source?.itemCode);
@@ -319,14 +479,9 @@
       }
       const data = modalApi.getData<{ formType: FormType; id?: number }>();
       formType.value = data.formType;
-      // 鏂板/琛ュ綍/缂栬緫鎬佸姞杞芥湭缁戝畾鎵规鐨勬墭鐩橈紝渚涖�岀粦瀹氭墭鐩樸�嶅閫変笅鎷変娇鐢�
-      palletOptionSource = [];
-      tonBagOptionSource = [];
-      palletOptions.splice(0);
-      tonBagOptions.splice(0);
-      palletKeyword = "";
-      tonBagKeyword = "";
-      // 鍏堟寕杞藉熀纭�琛ㄥ崟锛屽�欓�夋墭鐩�/鍚ㄨ鍦ㄥ悗鍙板姞杞斤紝閬垮厤鍙樉绀轰汉鍛橀厤缃殑绌虹獥鏈�
+      // 姣忔鎵撳紑閲嶇疆缁戝畾鍊欓�夛紝涓嬫媺鏀逛负婊氬姩鍒嗛〉鍔犺浇锛岄鎵瑰湪琛ㄥ崟鎸傝浇鍚庡紓姝ユ媺鍙�
+      resetBindingLoader(palletLoader, palletOptions, palletSelected);
+      resetBindingLoader(tonBagLoader, tonBagOptions, tonBagSelected);
       formApi.setState({
         schema: useFormSchema(
           formType.value,
@@ -337,34 +492,11 @@
         ),
       });
       if (formType.value !== "detail") {
-        const [pallets, tonBags] = await Promise.all([getUnboundPalletList(), getUnboundTonBags()]);
-        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,
-        }));
-        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);
-      }
-      // 閲嶆柊鍚屾涓�娆� Schema锛屼娇渚濊禆瀛楁涓殑鍔ㄦ�� options 绔嬪嵆鎷垮埌棣栨壒鍊欓�夐」
-      formApi.setState({
-        schema: useFormSchema(
-          formType.value,
-          palletOptions,
-          palletHandlers,
-          tonBagOptions,
-          tonBagHandlers
-        ),
-      });
-      if (formType.value !== "detail") {
-        // 娓呯┖涓婃鎵撳紑鏃跺嬀閫夌殑鎵樼洏锛岄伩鍏嶆畫鐣欏�艰瑙﹀彂銆屾壒娆¤繘鍏ョ敓浜т腑銆�
+        // 娓呯┖涓婃鎵撳紑鏃跺嬀閫夌殑鎵樼洏/鍚ㄨ锛岄伩鍏嶆畫鐣欏�艰瑙﹀彂銆屾壒娆¤繘鍏ョ敓浜т腑銆�
         await formApi.setFieldValue("palletIds", undefined);
         await formApi.setFieldValue("tonBagIds", undefined);
+        void loadPalletPage(true);
+        void loadTonBagPage(true);
       }
       // 鏍规嵁琛ㄥ崟鎬佸垏鎹汉鍛樺瓙琛ㄥ垪
       workerGridApi.setGridOptions({
@@ -379,6 +511,8 @@
           const existingBinding = formData.value.bindingMode;
           formApi.setState({ schema: useFormSchema(formType.value, palletOptions, palletHandlers, tonBagOptions, tonBagHandlers, existingBinding) });
           await formApi.setValues(formData.value);
+          // 宸叉湁缁戝畾浼氶攣瀹氬彟涓�渚т笅鎷夛紝閫夐」绂佺敤鎬侀渶瑕佹寜鏈�鏂拌〃鍗曞�奸噸绠�
+          await refreshBindingOptionState();
           const workers = (formData.value.workers ?? []).map(
             (worker, index) => ({ ...worker, _rowKey: worker.id ?? index })
           );

--
Gitblit v1.9.3