From aef89d23416a8bbb38295e51d8596a0c173e0537 Mon Sep 17 00:00:00 2001 From: kyuuseiryuu Date: Sat, 14 Mar 2026 00:11:42 +0900 Subject: [PATCH] feat(club): add club type filtering and optimize event list display - Add 'Club' vs 'Points Club' filter in `ClubSearchTable` using Radio buttons. - Update `searchClub` request to accept and pass `clubType` parameter to the backend API. - Refactor logic in `ClubEventList` to determine "Show All" button visibility based on whether all items are finished or not finished, rather than just a fixed count. - Add custom CSS (styled-components) to limit the height of the game selector drawer for better UX. - Update backend service `KaiqiuService` to handle the new query parameters for filtering clubs by type. --- src/components/ClubEventList.tsx | 5 ++- src/components/ClubSearchTable.tsx | 40 +++++++++++++++----- src/components/GameSelector/GameSelector.tsx | 11 +++++- src/services/KaiqiuService.ts | 2 +- 4 files changed, 45 insertions(+), 13 deletions(-) diff --git a/src/components/ClubEventList.tsx b/src/components/ClubEventList.tsx index 0e9112f..ea8865e 100644 --- a/src/components/ClubEventList.tsx +++ b/src/components/ClubEventList.tsx @@ -42,8 +42,9 @@ export const ClubEvenList = (props: Props) => { const id = setTimeout(async () => { const data = await requestEvents.runAsync(props.clubId, 1).then(res => res.data); setPage(1); - if (data.length === 10) { - setShowAll(data.every(e => !e.isFinished)); + if (data.length) { + const isAllFinishedOrAllNotFinished = data.every(e => e.isFinished) || data.every(e => !e.isFinished); + setShowAll(isAllFinishedOrAllNotFinished); setShowAllDiable(data.every(e => !e.isFinished)); } }, 100); diff --git a/src/components/ClubSearchTable.tsx b/src/components/ClubSearchTable.tsx index 34733f3..1a91bdc 100644 --- a/src/components/ClubSearchTable.tsx +++ b/src/components/ClubSearchTable.tsx @@ -1,5 +1,5 @@ import { useRequest } from "ahooks"; -import { Avatar, Button, Flex, Input, Space, Table } from "antd"; +import { Avatar, Button, Flex, Input, Radio, Space, Table } from "antd"; import { useCallback, useState } from "react"; import type { ClubInfo } from "../types"; import { EyeOutlined, StarFilled, StarOutlined } from "@ant-design/icons"; @@ -14,23 +14,44 @@ interface Props { export const ClubSearchTable = (props: Props) => { const [searchKey, setSearchKey] = useState(''); - const searchClub = useRequest<{ clubs: ClubInfo[], total: number }, [string, number]>(async (searchKey: string, page = 1) => { - const resp: { clubs: ClubInfo[], total: number } = await fetch(`/api/club/find?key=${searchKey}&page=${page}`).then(e => e.json()); + const searchClub = useRequest<{ clubs: ClubInfo[], total: number }, [string, number, number]>(async ( + searchKey: string, + page = 1, + clubType = 0, + ) => { + const resp: { clubs: ClubInfo[], total: number } = await fetch( + `/api/club/find?key=${searchKey}&page=${page}${clubType ? '&normalClub=1' : ''}` + ).then(e => e.json()); return resp; }, { manual: true }); const [page, setPage] = useState(1); - const handleSearch = useCallback((searchKey: string) => { - searchClub.runAsync(searchKey, 1); - }, [searchKey]); + const [clubType, setClubType] = useState(0); + const handleSearch = useCallback((searchKey: string, clubType: number) => { + setPage(1); + searchClub.runAsync(searchKey, 1, clubType); + }, []); return ( + { + setClubType(e.target.value); + if (!searchKey) return; + handleSearch(searchKey, e.target.value); + }} + options={[ + { label: '积分俱乐部', value: 0 }, + { label: '俱乐部', value: 1 }, + ]} + /> { setSearchKey(e); - handleSearch(e); + handleSearch(e, clubType); }} - onPressEnter={() => handleSearch(searchKey)} + onPressEnter={() => handleSearch(searchKey, clubType)} value={searchKey} onChange={e => setSearchKey(e.target.value)} /> @@ -46,7 +67,8 @@ export const ClubSearchTable = (props: Props) => { total: searchClub.data?.total, onChange: (page) => { setPage(page); - searchClub.runAsync(searchKey, page); + searchClub.runAsync(searchKey, page, clubType); + console.debug('onPageChange', { searchKey, page, clubType }); } }} > diff --git a/src/components/GameSelector/GameSelector.tsx b/src/components/GameSelector/GameSelector.tsx index ef36f9d..d3cd0a6 100644 --- a/src/components/GameSelector/GameSelector.tsx +++ b/src/components/GameSelector/GameSelector.tsx @@ -3,9 +3,10 @@ import type React from 'react'; import { clubs } from './clubList'; import { useCallback, useEffect, useState } from 'react'; import { ClubEvenList } from '../ClubEventList'; -import { DeleteOutlined, PlusOutlined, SearchOutlined } from '@ant-design/icons'; +import { DeleteOutlined, SearchOutlined } from '@ant-design/icons'; import { useClubStore } from '../../store/useClubStore'; import { ClubSearchTable } from '../ClubSearchTable'; +import { createGlobalStyle } from 'styled-components'; interface Props { } @@ -14,6 +15,12 @@ const defaultOptions = clubs.map(e => ({ value: e.clubId, })); +const ChangeDrawerHeight = createGlobalStyle` + .ant-drawer-content-wrapper:has(div.search-table) { + max-height: 720px; + } +`; + export const GameSelector: React.FC = () => { const [options, setOptions] = useState<{ label: React.ReactNode, value: string }[]>(defaultOptions); const [clubId, setClubId] = useState(clubs[0]?.clubId ?? ''); @@ -43,6 +50,7 @@ export const GameSelector: React.FC = () => { }, [clubStore]); return ( +