2
0
Эх сурвалжийг харах

🚀 feat: Align search API with channel listing & fix sorting toggle

1. Backend
   • `controller/channel.go`
     – Added pagination (`p`, `page_size`) support to `SearchChannels`.
     – Added independent `type` filter (keeps `type_counts` unaffected).
     – Returned `total`, `type_counts` to match `/api/channel/` response.

2. Frontend
   • `ChannelsTable.js`
     – `loadChannels` / `searchChannels` now pass `p`, `page_size`, `id_sort`, `type`, `status` correctly.
     – Pagination, page-size selector and type tabs work for both normal list and search mode.
     – Switch for “ID sort” calls proper API and keeps UI state in sync.
     – Removed unnecessary `normalize` helper; `getFormValues` back to concise form.

Result
• Search mode and normal listing now share identical pagination and filtering behavior.
• Type tabs show correct counts even after searching.
• “ID Sort” toggle no longer inverses actual behaviour.
t0ng7u 6 сар өмнө
parent
commit
aeb393e391

+ 41 - 1
controller/channel.go

@@ -300,11 +300,51 @@ func SearchChannels(c *gin.Context) {
 		typeCounts[int64(channel.Type)]++
 	}
 
+	typeParam := c.Query("type")
+	typeFilter := -1
+	if typeParam != "" {
+		if tp, err := strconv.Atoi(typeParam); err == nil {
+			typeFilter = tp
+		}
+	}
+
+	if typeFilter >= 0 {
+		filtered := make([]*model.Channel, 0, len(channelData))
+		for _, ch := range channelData {
+			if ch.Type == typeFilter {
+				filtered = append(filtered, ch)
+			}
+		}
+		channelData = filtered
+	}
+
+	page, _ := strconv.Atoi(c.DefaultQuery("p", "1"))
+	pageSize, _ := strconv.Atoi(c.DefaultQuery("page_size", "20"))
+	if page < 1 {
+		page = 1
+	}
+	if pageSize <= 0 {
+		pageSize = 20
+	}
+
+	total := len(channelData)
+	startIdx := (page - 1) * pageSize
+	if startIdx > total {
+		startIdx = total
+	}
+	endIdx := startIdx + pageSize
+	if endIdx > total {
+		endIdx = total
+	}
+
+	pagedData := channelData[startIdx:endIdx]
+
 	c.JSON(http.StatusOK, gin.H{
 		"success": true,
 		"message": "",
 		"data": gin.H{
-			"items":       channelData,
+			"items":       pagedData,
+			"total":       total,
 			"type_counts": typeCounts,
 		},
 	})

+ 38 - 16
web/src/components/table/ChannelsTable.js

@@ -886,7 +886,7 @@ const ChannelsTable = () => {
     const { searchKeyword, searchGroup, searchModel } = getFormValues();
     if (searchKeyword !== '' || searchGroup !== '' || searchModel !== '') {
       setLoading(true);
-      await searchChannels(enableTagMode, typeKey, statusF);
+      await searchChannels(enableTagMode, typeKey, statusF, page, pageSize, idSort);
       setLoading(false);
       return;
     }
@@ -947,7 +947,7 @@ const ChannelsTable = () => {
     if (searchKeyword === '' && searchGroup === '' && searchModel === '') {
       await loadChannels(activePage, pageSize, idSort, enableTagMode);
     } else {
-      await searchChannels(enableTagMode);
+      await searchChannels(enableTagMode, activeTypeKey, statusFilter, activePage, pageSize, idSort);
     }
   };
 
@@ -1053,7 +1053,7 @@ const ChannelsTable = () => {
     }
   };
 
-  // 获取表单值的辅助函数,确保所有值都是字符串
+  // 获取表单值的辅助函数
   const getFormValues = () => {
     const formValues = formApi ? formApi.getValues() : {};
     return {
@@ -1063,28 +1063,35 @@ const ChannelsTable = () => {
     };
   };
 
-  const searchChannels = async (enableTagMode, typeKey = activeTypeKey, statusF = statusFilter) => {
+  const searchChannels = async (
+    enableTagMode,
+    typeKey = activeTypeKey,
+    statusF = statusFilter,
+    page = 1,
+    pageSz = pageSize,
+    sortFlag = idSort,
+  ) => {
     const { searchKeyword, searchGroup, searchModel } = getFormValues();
-
     setSearching(true);
     try {
       if (searchKeyword === '' && searchGroup === '' && searchModel === '') {
-        await loadChannels(activePage - 1, pageSize, idSort, enableTagMode, typeKey, statusF);
+        await loadChannels(page, pageSz, sortFlag, enableTagMode, typeKey, statusF);
         return;
       }
 
       const typeParam = (typeKey !== 'all') ? `&type=${typeKey}` : '';
       const statusParam = statusF !== 'all' ? `&status=${statusF}` : '';
       const res = await API.get(
-        `/api/channel/search?keyword=${searchKeyword}&group=${searchGroup}&model=${searchModel}&id_sort=${idSort}&tag_mode=${enableTagMode}${typeParam}${statusParam}`,
+        `/api/channel/search?keyword=${searchKeyword}&group=${searchGroup}&model=${searchModel}&id_sort=${sortFlag}&tag_mode=${enableTagMode}&p=${page}&page_size=${pageSz}${typeParam}${statusParam}`,
       );
       const { success, message, data } = res.data;
       if (success) {
-        const { items = [], type_counts = {} } = data;
+        const { items = [], total = 0, type_counts = {} } = data;
         const sumAll = Object.values(type_counts).reduce((acc, v) => acc + v, 0);
         setTypeCounts({ ...type_counts, all: sumAll });
         setChannelFormat(items, enableTagMode);
-        setActivePage(1);
+        setChannelCount(total);
+        setActivePage(page);
       } else {
         showError(message);
       }
@@ -1292,19 +1299,29 @@ const ChannelsTable = () => {
   let pageData = channels;
 
   const handlePageChange = (page) => {
+    const { searchKeyword, searchGroup, searchModel } = getFormValues();
     setActivePage(page);
-    loadChannels(page, pageSize, idSort, enableTagMode).then(() => { });
+    if (searchKeyword === '' && searchGroup === '' && searchModel === '') {
+      loadChannels(page, pageSize, idSort, enableTagMode).then(() => { });
+    } else {
+      searchChannels(enableTagMode, activeTypeKey, statusFilter, page, pageSize, idSort);
+    }
   };
 
   const handlePageSizeChange = async (size) => {
     localStorage.setItem('page-size', size + '');
     setPageSize(size);
     setActivePage(1);
-    loadChannels(1, size, idSort, enableTagMode)
-      .then()
-      .catch((reason) => {
-        showError(reason);
-      });
+    const { searchKeyword, searchGroup, searchModel } = getFormValues();
+    if (searchKeyword === '' && searchGroup === '' && searchModel === '') {
+      loadChannels(1, size, idSort, enableTagMode)
+        .then()
+        .catch((reason) => {
+          showError(reason);
+        });
+    } else {
+      searchChannels(enableTagMode, activeTypeKey, statusFilter, 1, size, idSort);
+    }
   };
 
   const fetchGroups = async () => {
@@ -1615,7 +1632,12 @@ const ChannelsTable = () => {
               onChange={(v) => {
                 localStorage.setItem('id-sort', v + '');
                 setIdSort(v);
-                loadChannels(activePage, pageSize, v, enableTagMode);
+                const { searchKeyword, searchGroup, searchModel } = getFormValues();
+                if (searchKeyword === '' && searchGroup === '' && searchModel === '') {
+                  loadChannels(activePage, pageSize, v, enableTagMode);
+                } else {
+                  searchChannels(enableTagMode, activeTypeKey, statusFilter, activePage, pageSize, v);
+                }
               }}
             />
           </div>