154 lines
5.4 KiB
TypeScript
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>
|
|
);
|
|
} |