Răsfoiți Sursa

feat: 补货员设备绑定弹窗增加门店搜索和全选功能

- 新增搜索框按门店名称/地址过滤
- 全选复选框一键选中/取消所有设备,显示已选/总数
- 关闭弹窗自动重置搜索词

Co-Authored-By: Claude <noreply@anthropic.com>
skyline 3 zile în urmă
părinte
comite
adf93a8a99

+ 30 - 7
haha-admin-web/src/views/replenisher/index.vue

@@ -45,6 +45,12 @@ const {
   toggleShopSelectAll,
   getShopSelectState,
   handleConfirmBind,
+  shopSearchKeyword,
+  filteredShopTree,
+  allDevicesCount,
+  isAllSelected,
+  toggleSelectAll,
+  resetShopSearch,
   handleSizeChange,
   handleCurrentChange
 } = useReplenisher(tableRef);
@@ -184,23 +190,40 @@ const {
       width="600px"
       draggable
       :close-on-click-modal="false"
+      @close="resetShopSearch"
     >
       <div v-loading="loadingShopTree" class="bind-device-container">
+        <!-- 搜索 + 全选 -->
+        <div class="mb-3 flex items-center gap-3">
+          <el-input
+            v-model="shopSearchKeyword"
+            placeholder="搜索门店名称或地址"
+            clearable
+            size="small"
+            class="flex-1"
+            :prefix-icon="useRenderIcon('ri/search-line')"
+          />
+          <el-checkbox
+            :model-value="isAllSelected"
+            :indeterminate="selectedDeviceIds.size > 0 && !isAllSelected"
+            size="small"
+            @change="toggleSelectAll"
+          >
+            全选 {{ selectedDeviceIds.size }}/{{ allDevicesCount }}
+          </el-checkbox>
+        </div>
+
         <!-- 绑定状态摘要 -->
         <div class="mb-3 px-1 text-sm text-gray-500 flex items-center gap-1">
-          已选择
-          <span class="font-bold text-[var(--el-color-primary)]">{{ selectedDeviceIds.size }}</span>
-          台设备
-          <el-divider direction="vertical" />
           共 {{ shopDeviceTree.length }} 个门店
         </div>
 
         <!-- 门店设备列表 -->
-        <div v-if="shopDeviceTree.length === 0 && !loadingShopTree" class="py-8">
-          <el-empty description="暂无可用门店" />
+        <div v-if="filteredShopTree.length === 0 && !loadingShopTree" class="py-8">
+          <el-empty :description="shopSearchKeyword ? '未匹配到门店' : '暂无可用门店'" />
         </div>
 
-        <div v-for="shop in shopDeviceTree" :key="shop.id" class="mb-3 border rounded-lg overflow-hidden">
+        <div v-for="shop in filteredShopTree" :key="shop.id" class="mb-3 border rounded-lg overflow-hidden">
           <!-- 门店头部 -->
           <div
             class="flex items-center px-3 py-2.5 cursor-pointer select-none transition-colors hover:bg-gray-50"

+ 39 - 0
haha-admin-web/src/views/replenisher/utils/hook.tsx

@@ -20,6 +20,7 @@ import {
   type Ref,
   h,
   ref,
+  computed,
   toRaw,
   reactive,
   onMounted
@@ -202,6 +203,38 @@ export function useReplenisher(tableRef: Ref) {
   const loadingShopTree = ref(false);
   const selectedDeviceIds = ref<Set<string>>(new Set());
   const origBoundDeviceIds = ref<Set<string>>(new Set());
+  const shopSearchKeyword = ref("");
+
+  // 按搜索词过滤门店
+  const filteredShopTree = computed(() => {
+    const kw = shopSearchKeyword.value.trim().toLowerCase();
+    if (!kw) return shopDeviceTree.value;
+    return shopDeviceTree.value.filter(
+      s => s.name.toLowerCase().includes(kw) || s.address.toLowerCase().includes(kw)
+    );
+  });
+
+  // 全部设备是否已选中
+  const allDevicesCount = computed(() =>
+    shopDeviceTree.value.reduce((sum, s) => sum + s.devices.length, 0)
+  );
+  const isAllSelected = computed(() =>
+    allDevicesCount.value > 0 && selectedDeviceIds.value.size === allDevicesCount.value
+  );
+
+  function toggleSelectAll() {
+    if (isAllSelected.value) {
+      selectedDeviceIds.value = new Set();
+    } else {
+      const all = new Set<string>();
+      shopDeviceTree.value.forEach(s => s.devices.forEach(d => all.add(d.deviceId)));
+      selectedDeviceIds.value = all;
+    }
+  }
+
+  function resetShopSearch() {
+    shopSearchKeyword.value = "";
+  }
 
   async function openBindDialog(row: ReplenisherFormItem) {
     currentReplenisher.value = row;
@@ -595,6 +628,12 @@ export function useReplenisher(tableRef: Ref) {
     toggleShopSelectAll,
     getShopSelectState,
     handleConfirmBind,
+    shopSearchKeyword,
+    filteredShopTree,
+    allDevicesCount,
+    isAllSelected,
+    toggleSelectAll,
+    resetShopSearch,
     handleSizeChange,
     handleCurrentChange
   };