浏览代码

refactor TreeSelect component

Olivier Massot 4 月之前
父节点
当前提交
7980db82d3
共有 1 个文件被更改,包括 123 次插入100 次删除
  1. 123 100
      components/Ui/Input/TreeSelect.vue

+ 123 - 100
components/Ui/Input/TreeSelect.vue

@@ -169,106 +169,6 @@ const onMenuUpdate = (isOpen: boolean) => {
   }
 }
 
-/**
- * A computed property that generates a flattened and organized list of items
- * from a hierarchical structure, based on the current search text and
- * expanded categories/subcategories.
- *
- * Logic:
- * - If there is a search text:
- *   - Filters items to include only level 2 items matching the search text.
- *   - Ensures parent categories and subcategories are added to the result.
- *   - Expands categories and subcategories relevant to search results.
- * - Without a search text:
- *   - Recursively processes items to include all relevant categories,
- *     subcategories, and individual items based on the expanded states.
- *
- * @returns {SelectItem[]} Flattened and organized list of items.
- */
-const flattenedItems = computed(() => {
-  const result: SelectItem[] = []
-  const hasSearch = !!searchText.value.trim()
-  // TODO: simplifier et découper
-
-  // Si une recherche est active, afficher uniquement les éléments de niveau 2 qui correspondent
-  if (hasSearch) {
-    // Trouver tous les éléments de niveau 2 qui correspondent à la recherche
-    const matchingItems = props.items.filter(item =>
-      item.type === 'item' &&
-      item.level === 2 &&
-      itemMatchesSearch(item)
-    )
-
-    // Ensemble pour suivre les catégories et sous-catégories déjà ajoutées
-    const addedCategoryIds = new Set<string>()
-    const addedSubcategoryIds = new Set<string>()
-
-    // Pour chaque élément correspondant, ajouter sa hiérarchie complète
-    for (const item of matchingItems) {
-      // Trouver la sous-catégorie parente
-      const subcategory = props.items.find(i => i.id === item.parentId)
-      if (!subcategory) continue
-
-      // Trouver la catégorie parente
-      const category = props.items.find(i => i.id === subcategory.parentId)
-      if (!category) continue
-
-      // Ajouter la catégorie si elle n'est pas déjà présente
-      if (!addedCategoryIds.has(category.id)) {
-        result.push(category)
-        addedCategoryIds.add(category.id)
-        // S'assurer que la catégorie est considérée comme "expanded" pendant la recherche
-        expandedCategories.value.add(category.id)
-      }
-
-      // Ajouter la sous-catégorie si elle n'est pas déjà présente
-      if (!addedSubcategoryIds.has(subcategory.id)) {
-        result.push(subcategory)
-        addedSubcategoryIds.add(subcategory.id)
-        // S'assurer que la sous-catégorie est considérée comme "expanded" pendant la recherche
-        expandedSubcategories.value.add(subcategory.id)
-      }
-
-      // Ajouter l'élément
-      result.push(item)
-    }
-
-    return result
-  }
-
-  // Comportement normal sans recherche
-  const processItems = (items: SelectItem[], parentExpanded = true) => {
-    for (const item of items) {
-      if (item.type === 'category') {
-        result.push(item)
-        if (expandedCategories.value.has(item.id)) {
-          const subcategories = props.items.filter(i =>
-            i.parentId === item.id && i.type === 'subcategory'
-          )
-          processItems(subcategories, true)
-        }
-      } else if (item.type === 'subcategory') {
-        if (parentExpanded) {
-          result.push(item)
-          if (expandedSubcategories.value.has(item.id)) {
-            const subItems = props.items.filter(i =>
-              i.parentId === item.id && i.type === 'item'
-            )
-            processItems(subItems, true)
-          }
-        }
-      } else if (item.type === 'item' && parentExpanded) {
-        result.push(item)
-      }
-    }
-  }
-
-  const topLevelItems = props.items.filter(item => !item.parentId)
-  processItems(topLevelItems)
-
-  return result
-})
-
 /**
  * Toggles the expanded state of a given category. If the category is currently
  * expanded, it will collapse the category and also collapse its subcategories.
@@ -410,6 +310,129 @@ const itemMatchesSearch = (item: SelectItem): boolean => {
   // Pour les autres types d'éléments, vérifier simplement leur label
   return StringUtils.normalize(item.label).includes(normalizedSearch)
 }
+
+/**
+ * Filtre les éléments de niveau 2 qui correspondent au texte de recherche.
+ *
+ * @returns {SelectItem[]} Les éléments de niveau 2 qui correspondent à la recherche.
+ */
+const findMatchingLevel2Items = (): SelectItem[] => {
+  return props.items.filter(item =>
+    item.type === 'item' &&
+    item.level === 2 &&
+    itemMatchesSearch(item)
+  )
+}
+
+/**
+ * Construit une liste hiérarchique d'éléments basée sur les résultats de recherche.
+ * Pour chaque élément correspondant, ajoute sa hiérarchie complète (catégorie et sous-catégorie).
+ *
+ * @param {SelectItem[]} matchingItems - Les éléments correspondant à la recherche.
+ * @returns {SelectItem[]} Liste hiérarchique incluant les éléments et leurs parents.
+ */
+const buildSearchResultsList = (matchingItems: SelectItem[]): SelectItem[] => {
+  const result: SelectItem[] = []
+  const addedCategoryIds = new Set<string>()
+  const addedSubcategoryIds = new Set<string>()
+
+  for (const item of matchingItems) {
+    // Trouver la sous-catégorie parente
+    const subcategory = props.items.find(i => i.id === item.parentId)
+    if (!subcategory) continue
+
+    // Trouver la catégorie parente
+    const category = props.items.find(i => i.id === subcategory.parentId)
+    if (!category) continue
+
+    // Ajouter la catégorie si elle n'est pas déjà présente
+    if (!addedCategoryIds.has(category.id)) {
+      result.push(category)
+      addedCategoryIds.add(category.id)
+      expandedCategories.value.add(category.id)
+    }
+
+    // Ajouter la sous-catégorie si elle n'est pas déjà présente
+    if (!addedSubcategoryIds.has(subcategory.id)) {
+      result.push(subcategory)
+      addedSubcategoryIds.add(subcategory.id)
+      expandedSubcategories.value.add(subcategory.id)
+    }
+
+    // Ajouter l'élément
+    result.push(item)
+  }
+
+  return result
+}
+
+/**
+ * Traite récursivement les éléments pour construire une liste hiérarchique
+ * basée sur l'état d'expansion des catégories et sous-catégories.
+ *
+ * @param {SelectItem[]} items - Les éléments à traiter.
+ * @param {SelectItem[]} result - Le tableau résultat à remplir.
+ * @param {boolean} parentExpanded - Indique si le parent est développé.
+ */
+const processItemsRecursively = (
+  items: SelectItem[],
+  result: SelectItem[],
+  parentExpanded = true
+): void => {
+  for (const item of items) {
+    if (item.type === 'category') {
+      result.push(item)
+      if (expandedCategories.value.has(item.id)) {
+        const subcategories = props.items.filter(i =>
+          i.parentId === item.id && i.type === 'subcategory'
+        )
+        processItemsRecursively(subcategories, result, true)
+      }
+    } else if (item.type === 'subcategory') {
+      if (parentExpanded) {
+        result.push(item)
+        if (expandedSubcategories.value.has(item.id)) {
+          const subItems = props.items.filter(i =>
+            i.parentId === item.id && i.type === 'item'
+          )
+          processItemsRecursively(subItems, result, true)
+        }
+      }
+    } else if (item.type === 'item' && parentExpanded) {
+      result.push(item)
+    }
+  }
+}
+
+/**
+ * Construit une liste hiérarchique d'éléments en mode normal (sans recherche).
+ *
+ * @returns {SelectItem[]} Liste hiérarchique basée sur l'état d'expansion.
+ */
+const buildNormalModeList = (): SelectItem[] => {
+  const result: SelectItem[] = []
+  const topLevelItems = props.items.filter(item => !item.parentId)
+  processItemsRecursively(topLevelItems, result)
+  return result
+}
+
+/**
+ * A computed property that generates a flattened and organized list of items
+ * from a hierarchical structure, based on the current search text and
+ * expanded categories/subcategories.
+ *
+ * @returns {SelectItem[]} Flattened and organized list of items.
+ */
+const flattenedItems = computed(() => {
+  const hasSearch = !!searchText.value.trim()
+
+  if (hasSearch) {
+    const matchingItems = findMatchingLevel2Items()
+    return buildSearchResultsList(matchingItems)
+  }
+
+  return buildNormalModeList()
+})
 </script>
 
 <style scoped lang="scss">