my-kaiqiuwang/src/components/ClubSearchTable.tsx

154 lines
5.4 KiB
TypeScript

import { useRequest } from "ahooks";
import { Avatar, Button, Flex, Input, Radio, Space, Table } from "antd";
import { useCallback, useRef, useState } from "react";
import type { ClubInfo } from "@/types";
import { EyeOutlined, StarFilled, StarOutlined } from "@ant-design/icons";
import { useClubStore } from "@/store/useClubStore";
import { CascaderProvinceCity } from "./CascaderProvinceCity";
type ClickType = 'VIEW' | 'FAV';
interface Props {
handleClick?: (type: ClickType, club: ClubInfo) => void;
}
enum ClubType {
,
,
,
}
type Data = { clubs: Pick<ClubInfo, 'id' | 'name'>[], total: number, page: number; };
const initData = { clubs: [], total: 0, page: 1 };
export const ClubSearchTable = (props: Props) => {
const [searchKey, setSearchKey] = useState('');
const [provinceCity, setProvinceCity] = useState<{ province?: string, city?: string }>({ province: '', city: '' });
const [datasource, setDatasource] = useState<Data>(initData);
const dataRef = useRef<Partial<Record<ClubType, Data>>>({});
const searchClub = useRequest<Data, [string, number, ClubType]>(async (
searchKey: string,
page = 1,
clubType = ClubType.,
) => {
const searchParams = new URLSearchParams();
searchParams.append('key', searchKey);
searchParams.append('page', page.toString());
searchParams.append('province', provinceCity.province ?? '');
searchParams.append('city', provinceCity.city ?? '');
if (clubType) {
searchParams.append('normalClub', '1');
}
const resp: Data = await fetch(
`/api/club/find?${searchParams.toString()}`
).then(e => e.json());
dataRef.current[clubType] = {
...resp,
page,
};
return resp;
}, { manual: true, refreshDeps: [provinceCity] });
const clubStore = useClubStore(store => store);
const [clubType, setClubType] = useState<ClubType>(ClubType.);
const handleSearch = useCallback(async (searchKey: string, clubType: ClubType, page = 1) => {
switch (clubType) {
case ClubType.积分俱乐部:
case ClubType.: {
const resp = await searchClub.runAsync(searchKey, page, clubType);
setDatasource({ ...resp, page });
break;
}
}
}, []);
const handleTypeChange = useCallback(async (type: ClubType) => {
setClubType(type);
switch (type) {
case ClubType.积分俱乐部:
case ClubType.: {
if (!searchKey) {
setDatasource(dataRef.current[type] ?? initData);
break;
}
await handleSearch(searchKey, type);
break;
}
case ClubType.我的收藏:
setDatasource({ clubs: clubStore.clubs, total: clubStore.clubs.length, page: 1 });
break;
default: break;
}
}, [searchKey, searchClub, clubStore]);
return (
<Flex vertical gap={12} justify="center" align="center">
<Radio.Group
optionType="button"
value={clubType}
onChange={e => handleTypeChange(e.target.value)}
options={[
{ label: '积分俱乐部', value: ClubType.积分俱乐部 },
{ label: '俱乐部', value: ClubType.俱乐部 },
{ label: '我的收藏', value: ClubType.我的收藏 },
]}
/>
{clubType !== ClubType. ? (
<Flex wrap gap={8} style={{ width: '100%', minWidth: 180 }}>
<Flex flex={1}>
<CascaderProvinceCity onChange={(province, city) => setProvinceCity({ province, city })} />
</Flex>
<Flex flex={2} style={{ width: '100%', minWidth: 200 }}>
<Input.Search
allowClear
onSearch={e => {
setSearchKey(e);
handleSearch(e, clubType);
}}
onPressEnter={() => handleSearch(searchKey, clubType)}
value={searchKey}
onChange={e => setSearchKey(e.target.value)}
/>
</Flex>
</Flex>
) : null}
<Table
rowKey={e => e.id}
loading={searchClub.loading}
dataSource={datasource.clubs}
style={{ width: '100%' }}
scroll={{ x: 400 }}
pagination={clubType !== ClubType. ? {
current: datasource.page,
showSizeChanger: false,
total: datasource.total,
onChange: (page) => {
handleSearch(searchKey, clubType, page);
}
} : false}
>
<Table.Column dataIndex="name" width={140} fixed="left" render={(name, { img }) => {
return (
<Space>
<Avatar src={img} size={32} />
<span>{name}</span>
</Space>
);
}} />
<Table.Column dataIndex="area" width={80} />
<Table.Column dataIndex="members" width={80} render={num => `${num}`} />
<Table.Column dataIndex="id" align="center" width={200} render={(id, record: ClubInfo) => {
return (
<Space.Compact size="small">
<Button icon={
useClubStore.getState().isFav(id)
? <StarFilled style={{ color: 'yellow' }} />
: <StarOutlined />
} onClick={() => props.handleClick?.('FAV', record)}></Button>
<Button icon={<EyeOutlined />} onClick={() => props.handleClick?.('VIEW', record)}></Button>
</Space.Compact>
);
}} />
</Table>
</Flex>
);
}