Merge branch 'feature/juguohong/20250816'

This commit is contained in:
李瑞
2025-09-13 17:51:08 +08:00
15 changed files with 228 additions and 194 deletions

View File

@@ -9,12 +9,12 @@ interface IProps {
const CustomNavbar = (props: IProps) => { const CustomNavbar = (props: IProps) => {
const { children } = props; const { children } = props;
const { statusNavbarHeightInfo } = useGlobalState(); const { statusNavbarHeightInfo } = useGlobalState();
const { totalHeight } = statusNavbarHeightInfo; const { statusBarHeight, navbarHeight } = statusNavbarHeightInfo;
return ( return (
<View <View
className={styles.customerNavbar} className={styles.customerNavbar}
style={{ height: `${totalHeight}px` }} style={{ height: `${navbarHeight}px`, paddingTop: `${statusBarHeight}px`, }}
> >
{children} {children}
</View> </View>

View File

@@ -1,5 +1,6 @@
.distanceQuickFilterWrap { .distanceQuickFilterWrap {
width: 100%; width: 100%;
--nutui-menu-bar-line-height: 30px;
.nut-menu-bar { .nut-menu-bar {
background-color: unset; background-color: unset;
@@ -35,19 +36,6 @@
border-bottom-right-radius: 30px; border-bottom-right-radius: 30px;
} }
// .nut-menu-container-item {
// color: rgba(60, 60, 67, 0.6);
// font-size: 14px;
// font-weight: 600;
// line-height: 20px;
// }
// .nut-menu-container-item.active {
// flex-direction: row-reverse;
// justify-content: space-between;
// color: #000;
// }
.positionWrap { .positionWrap {
display: flex; display: flex;
align-items: center; align-items: center;

View File

@@ -1,11 +1,11 @@
import React, { useEffect, useRef, useState } from "react"; import { useRef, useState } from "react";
import { Menu, Button } from "@nutui/nutui-react-taro"; import { Menu } from "@nutui/nutui-react-taro";
import { Image, View, Text } from "@tarojs/components"; import { Image, View } from "@tarojs/components";
import img from "@/config/images"; import img from "@/config/images";
import Bubble from "../Bubble"; import Bubble from "../Bubble";
import "./index.scss"; import "./index.scss";
const Demo3 = (props) => { const DistanceQuickFilter = (props) => {
const { const {
cityOptions, cityOptions,
quickOptions, quickOptions,
@@ -49,6 +49,7 @@ const Demo3 = (props) => {
}; };
return ( return (
<View>
<Menu <Menu
className={`distanceQuickFilterWrap ${filterWrapperClassName}`} className={`distanceQuickFilterWrap ${filterWrapperClassName}`}
> >
@@ -105,6 +106,7 @@ const Demo3 = (props) => {
</View> </View>
</Menu.Item> </Menu.Item>
</Menu> </Menu>
</View>
); );
}; };
export default Demo3; export default DistanceQuickFilter;

View File

@@ -1,4 +1,4 @@
import { useMemo, useState } from "react"; import { useMemo } from "react";
import { Popup } from "@nutui/nutui-react-taro"; import { Popup } from "@nutui/nutui-react-taro";
import Range from "../../components/Range"; import Range from "../../components/Range";
import Bubble from "../../components/Bubble"; import Bubble from "../../components/Bubble";
@@ -29,7 +29,7 @@ const FilterPopup = (props: FilterPopupProps) => {
} = props; } = props;
const store = useListStore() || {}; const store = useListStore() || {};
const { getDictionaryValue } = useDictionaryActions() || {}; const { getDictionaryValue } = useDictionaryActions() || {};
const { timeBubbleData, gamesNum, dateRangeOptions } = store; const { timeBubbleData, gamesNum } = store;
/** /**
* @description 处理字典选项 * @description 处理字典选项
@@ -91,7 +91,7 @@ const FilterPopup = (props: FilterPopupProps) => {
round round
visible={visible} visible={visible}
onClose={onClose} onClose={onClose}
style={{ marginTop: statusNavbarHeigh + "px" }} style={{ marginTop: statusNavbarHeigh + "px", maxHeight: '75vh' }}
overlayStyle={{ marginTop: statusNavbarHeigh + "px" }} overlayStyle={{ marginTop: statusNavbarHeigh + "px" }}
zIndex={1001} zIndex={1001}
> >

View File

@@ -269,6 +269,15 @@
display: flex; display: flex;
align-items: center; align-items: center;
gap: 5px; gap: 5px;
flex-shrink: 0;
}
.localAreaWrapper {
max-width: 69%;
}
.localAreaTitle {
flex-shrink: 0;
} }
.smoothTitle { .smoothTitle {
@@ -291,5 +300,11 @@
.localArea { .localArea {
border: 0.5px solid #FFFFFFA6; border: 0.5px solid #FFFFFFA6;
border-radius: 50%; border-radius: 50%;
flex-shrink: 0;
}
.localAreaText {
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
} }
} }

View File

@@ -18,7 +18,21 @@ const ListCard: React.FC<ListCardProps> = ({
image_list = [], image_list = [],
court_type, court_type,
key, key,
participants, // 参与者图片
venue_image_list, // 场馆图片
venue_description,
game_type, // 球局类型
}) => { }) => {
// 参与者要前三个数据
const participantsImageList = participants?.slice(0, 3) || [];
// 场地 要第一个数据
// const venueImageList = venue_image_list?.slice(0, 1) || [];
const venueImage = venue_image_list?.[0]?.url || '';
// 是否显示畅打球局
const isShowSmoothPlayingGame = game_type === '畅打球局';
const renderItemImage = (src: string) => { const renderItemImage = (src: string) => {
return ( return (
<Image <Image
@@ -32,7 +46,6 @@ const ListCard: React.FC<ListCardProps> = ({
}; };
const handleViewDetail = () => { const handleViewDetail = () => {
console.log("id", id);
Taro.navigateTo({ Taro.navigateTo({
url: `/game_pages/detail/index?id=${id || 1}&from=list`, url: `/game_pages/detail/index?id=${id || 1}&from=list`,
}); });
@@ -120,11 +133,11 @@ const ListCard: React.FC<ListCardProps> = ({
<View className="bottom-info"> <View className="bottom-info">
<View className="left-section"> <View className="left-section">
<View className="avatar-group"> <View className="avatar-group">
{Array.from({ length: 3 }).map((_, index) => ( {(participantsImageList || []).map((item, index) => (
<View key={index} className="avatar"> <View key={index} className="avatar">
<Image <Image
className="avatar-image" className="avatar-image"
src="https://images.unsplash.com/photo-1554068865-24cecd4e34b8?w=200&h=200&fit=crop&crop=center" src={item?.user?.avatar_url}
mode="aspectFill" mode="aspectFill"
/> />
</View> </View>
@@ -157,24 +170,24 @@ const ListCard: React.FC<ListCardProps> = ({
<View className="image-section">{renderImages()}</View> <View className="image-section">{renderImages()}</View>
</View> </View>
{/* 畅打球局 */} {/* 畅打球局 */}
<View className="smoothPlayingGame"> {isShowSmoothPlayingGame && <View className="smoothPlayingGame">
<View className="smoothWrapper"> <View className="smoothWrapper">
<Image <Image
src={img.ICON_LIST_PLAYING_GAME} src={img.ICON_LIST_PLAYING_GAME}
className="iconListPlayingGame" className="iconListPlayingGame"
/> />
<Text className="smoothTitle"></Text> <Text className="smoothTitle">{game_type}</Text>
</View> </View>
<View className="line" /> <View className="line" />
<View>:</View> <View className="localAreaTitle">:</View>
<View className="localAreaWrapper"> <View className="localAreaWrapper">
<Image <Image
className="localArea" className="localArea"
src="https://images.unsplash.com/photo-1554068865-24cecd4e34b8?w=200&h=200&fit=crop&crop=center" src={venueImage}
/> />
<Text className="localAreaText"></Text> <Text className="localAreaText">{venue_description}</Text>
</View> </View>
</View> </View>}
</View> </View>
); );
}; };

View File

@@ -2,9 +2,8 @@ import { View } from "@tarojs/components";
import ListCard from "@/components/ListCard"; import ListCard from "@/components/ListCard";
import ListLoadError from "@/components/ListLoadError"; import ListLoadError from "@/components/ListLoadError";
import ListCardSkeleton from "@/components/ListCardSkeleton"; import ListCardSkeleton from "@/components/ListCardSkeleton";
// import { VirtualList } from '@nutui/nutui-react-taro'
import "./index.scss";
import { useReachBottom } from "@tarojs/taro"; import { useReachBottom } from "@tarojs/taro";
import "./index.scss";
const ListContainer = (props) => { const ListContainer = (props) => {
const { const {
@@ -12,14 +11,12 @@ const ListContainer = (props) => {
data = [], data = [],
error, error,
reload, reload,
recommendList, // recommendList,
loadMoreMatches, loadMoreMatches,
} = props; } = props;
console.log("===data", data);
useReachBottom(() => { useReachBottom(() => {
console.log("触底了"); // 加载更多方法
// 调用 store 的加载更多方法
loadMoreMatches(); loadMoreMatches();
}); });
@@ -39,17 +36,6 @@ const ListContainer = (props) => {
// 渲染列表 // 渲染列表
const renderList = (list) => { const renderList = (list) => {
// 请求未回来显示骨架屏
// if (loading && list?.length === 0) {
// return (
// <>
// {new Array(10).fill(0).map(() => {
// return <ListCardSkeleton />;
// })}
// </>
// );
// }
// 请求数据为空 // 请求数据为空
if (!loading && list?.length === 0) { if (!loading && list?.length === 0) {
return <ListLoadError reload={reload} text="暂无数据" />; return <ListLoadError reload={reload} text="暂无数据" />;
@@ -58,15 +44,6 @@ const ListContainer = (props) => {
// 渲染数据 // 渲染数据
return ( return (
<> <>
{/* <VirtualList
containerHeight={1000}
itemHeight={144}
// itemEqual={false}
list={list}
itemRender={(data) => {
return <ListCard {...data}/>
}}
/> */}
{list?.map((match, index) => ( {list?.map((match, index) => (
<ListCard key={match.id || index} {...match} /> <ListCard key={match.id || index} {...match} />
))} ))}
@@ -76,15 +53,25 @@ const ListContainer = (props) => {
return ( return (
<View className="listContentWrapper"> <View className="listContentWrapper">
{renderList(data)} {/* <ScrollView
{/* 显示骨架屏 */} scrollY
{loading && renderSkeleton()} scrollWithAnimation
{/* <View className="recommendTextWrapper"> enableBackToTop
enablePassive
style={{ height: '100vh' }}
onScrollToLower={handleScrollToLower}
upperThreshold={60}
> */}
{renderList(data)}
{/* 显示骨架屏 */}
{loading && renderSkeleton()}
{/* <View className="recommendTextWrapper">
<Text className="recommendText">搜索结果较少,已为你推荐其他内容</Text> <Text className="recommendText">搜索结果较少,已为你推荐其他内容</Text>
</View> </View>
{renderList(recommendList)} */} {renderList(recommendList)} */}
{/* 到底了 */} {/* 到底了 */}
{data?.length > 0 && <View className="bottomTextWrapper"></View>} {data?.length > 0 && <View className="bottomTextWrapper"></View>}
{/* </ScrollView> */}
</View> </View>
); );
}; };

View File

@@ -113,28 +113,31 @@
width: 100%; width: 100%;
height: 100%; height: 100%;
/* 过渡动画设置,实现平滑切换 */ /* 启用硬件加速 */
transition: opacity 0.5s ease, transform 0.5s ease; will-change: opacity, transform;
backface-visibility: hidden;
-webkit-backface-visibility: hidden;
/* 优化过渡动画,使用更快的缓动函数 */
transition: opacity 0.3s cubic-bezier(0.4, 0, 0.2, 1),
transform 0.3s cubic-bezier(0.4, 0, 0.2, 1);
} }
/* 第一个元素样式 */ /* 第一个元素样式 */
.firstElement { .firstElement {
// background-color: #4a90e2;
} }
/* 第二个元素样式 */ /* 第二个元素样式 */
.secondElement { .secondElement {
// background-color: #5cb85c;
/* 初始状态:透明且稍微偏移 */ /* 初始状态:透明且稍微偏移 */
opacity: 0; opacity: 0;
// transform: translateY(20px); transform: translateY(10px);
} }
/* 隐藏状态 */ /* 隐藏状态 */
.hidden { .hidden {
opacity: 0; opacity: 0;
transform: translateY(20px); transform: translateY(10px);
// pointer-events: none; /* 隐藏时不响应鼠标事件 */
} }
/* 可见状态 */ /* 可见状态 */

View File

@@ -2,7 +2,6 @@ import { View, Text, Image } from "@tarojs/components";
import img from "@/config/images"; import img from "@/config/images";
import { useGlobalState } from "@/store/global"; import { useGlobalState } from "@/store/global";
import { useUserInfo, } from '@/store/userStore' import { useUserInfo, } from '@/store/userStore'
import { useListState } from "@/store/listStore"; import { useListState } from "@/store/listStore";
import CustomNavbar from "@/components/CustomNavbar"; import CustomNavbar from "@/components/CustomNavbar";
import { Input } from "@nutui/nutui-react-taro"; import { Input } from "@nutui/nutui-react-taro";
@@ -26,13 +25,11 @@ const ListHeader = (props: IProps) => {
leftIconClick, leftIconClick,
} = config || {}; } = config || {};
const { const {
location,
getLocationText,
getLocationLoading, getLocationLoading,
statusNavbarHeightInfo, statusNavbarHeightInfo,
} = useGlobalState(); } = useGlobalState();
const { gamesNum, searchValue, isShowInputCustomerNavBar } = useListState(); const { gamesNum, searchValue, isShowInputCustomerNavBar } = useListState();
const { statusBarHeight, navbarHeight } = statusNavbarHeightInfo; const { navbarHeight } = statusNavbarHeightInfo;
const { city,district } = useUserInfo() const { city,district } = useUserInfo()
@@ -68,6 +65,11 @@ const ListHeader = (props: IProps) => {
} }
}; };
const navbarStyle = {
height: `${navbarHeight}px`,
paddingTop: `4px`,
};
return ( return (
<CustomNavbar> <CustomNavbar>
<View className="listNavWrapper"> <View className="listNavWrapper">
@@ -75,10 +77,7 @@ const ListHeader = (props: IProps) => {
<View <View
className={`listNavContainer toggleElement firstElement hidden ${(!isShowInputCustomerNavBar && !showInput) && "visible" className={`listNavContainer toggleElement firstElement hidden ${(!isShowInputCustomerNavBar && !showInput) && "visible"
}`} }`}
style={{ style={navbarStyle}
height: `${navbarHeight}px`,
paddingTop: `${statusBarHeight}px`,
}}
> >
<View className="listNavContentWrapper"> <View className="listNavContentWrapper">
{/* logo */} {/* logo */}
@@ -106,10 +105,7 @@ const ListHeader = (props: IProps) => {
<View <View
className={`inputCustomerNavbarContainer toggleElement secondElement hidden ${(isShowInputCustomerNavBar || showInput) && "visible" className={`inputCustomerNavbarContainer toggleElement secondElement hidden ${(isShowInputCustomerNavBar || showInput) && "visible"
} ${showInput && "inputCustomerNavbarShowInput"}`} } ${showInput && "inputCustomerNavbarShowInput"}`}
style={{ style={navbarStyle}
height: `${navbarHeight}px`,
paddingTop: `${statusBarHeight}px`,
}}
> >
<View className="navContent"> <View className="navContent">
{/* logo */} {/* logo */}
@@ -137,4 +133,5 @@ const ListHeader = (props: IProps) => {
</CustomNavbar> </CustomNavbar>
); );
}; };
export default ListHeader; export default ListHeader;

View File

@@ -18,6 +18,9 @@
padding-top: 10px; padding-top: 10px;
padding-bottom: 10px; padding-bottom: 10px;
gap: 5px; gap: 5px;
position: sticky;
background-color: #fff;
z-index: 100;
} }
.menuFilter { .menuFilter {

View File

@@ -1,7 +1,7 @@
import SearchBar from "@/components/SearchBar"; import SearchBar from "@/components/SearchBar";
import FilterPopup from "@/components/FilterPopup"; import FilterPopup from "@/components/FilterPopup";
import styles from "./index.module.scss"; import styles from "./index.module.scss";
import { useEffect } from "react"; import { useEffect, useRef } from "react";
import Taro, { usePageScroll } from "@tarojs/taro"; import Taro, { usePageScroll } from "@tarojs/taro";
import { useListStore } from "@/store/listStore"; import { useListStore } from "@/store/listStore";
import { useGlobalState } from "@/store/global"; import { useGlobalState } from "@/store/global";
@@ -12,11 +12,6 @@ import ListContainer from "@/container/listContainer";
import DistanceQuickFilter from "@/components/DistanceQuickFilter"; import DistanceQuickFilter from "@/components/DistanceQuickFilter";
import { withAuth } from "@/components"; import { withAuth } from "@/components";
import { updateUserLocation } from "@/services/userService"; import { updateUserLocation } from "@/services/userService";
// import img from "@/config/images";
// import ShareCardCanvas from "@/components/ShareCardCanvas/example";
const ListPage = () => { const ListPage = () => {
@@ -46,23 +41,28 @@ const ListPage = () => {
isShowInputCustomerNavBar, isShowInputCustomerNavBar,
initialFilterSearch, initialFilterSearch,
loadMoreMatches, loadMoreMatches,
dateRangeOptions fetchGetGamesCount
} = store; } = store;
// 简化的滚动处理函数
usePageScroll((res) => { usePageScroll((res) => {
if (res?.scrollTop >= totalHeight) { const shouldShowInputNav = res?.scrollTop >= totalHeight;
!isShowInputCustomerNavBar &&
// 只有当状态需要改变时才更新
if (shouldShowInputNav && !isShowInputCustomerNavBar) {
updateState({ isShowInputCustomerNavBar: true }); updateState({ isShowInputCustomerNavBar: true });
} else { } else if (!shouldShowInputNav && isShowInputCustomerNavBar) {
isShowInputCustomerNavBar &&
updateState({ isShowInputCustomerNavBar: false }); updateState({ isShowInputCustomerNavBar: false });
} }
}); });
const scrollContextRef = useRef(null)
useEffect(() => { useEffect(() => {
getLocation() getLocation()
}, []); }, []);
// 监听距离和排序方式变化,自动调用接口 // 监听距离和排序方式变化,自动调用接口
useEffect(() => { useEffect(() => {
// 只有当 distanceQuickFilter 有值时才调用接口 // 只有当 distanceQuickFilter 有值时才调用接口
@@ -89,6 +89,7 @@ const ListPage = () => {
console.error('更新用户位置失败:', error); console.error('更新用户位置失败:', error);
} }
} }
fetchGetGamesCount();
// 页面加载时获取数据 // 页面加载时获取数据
getMatchesData(); getMatchesData();
@@ -104,35 +105,45 @@ const ListPage = () => {
// } // }
// 下拉刷新处理函数 - 使用Taro生命周期钩子 // 下拉刷新处理函数 - 使用Taro生命周期钩子
Taro.usePullDownRefresh(() => { Taro.usePullDownRefresh(async () => {
console.log("===触发下拉刷新"); try {
clearFilterOptions() // 调用刷新方法
await refreshMatches();
// 调用 store 的刷新方法 // 刷新完成后停止下拉刷新动画
// refreshMatches() Taro.stopPullDownRefresh();
// .then(() => {
// // 刷新完成后停止下拉刷新动画
// Taro.stopPullDownRefresh();
// // 显示刷新成功提示 // 显示刷新成功提示
// Taro.showToast({ Taro.showToast({
// title: "刷新成功", title: "刷新成功",
// icon: "success", icon: "success",
// duration: 1500, duration: 1500,
// }); });
// }) } catch (error) {
// .catch(() => { // 刷新失败时也停止动画
// // 刷新失败时也停止动画 Taro.stopPullDownRefresh();
// Taro.stopPullDownRefresh();
// Taro.showToast({ Taro.showToast({
// title: "刷新失败", title: "刷新失败,请重试",
// icon: "error", icon: "error",
// duration: 1500, duration: 1500,
// }); });
// }); }
}); });
/**
* @description 综合筛选确认
* @returns
*/
const handleFilterConfirm = () => {
toggleShowPopup();
getMatchesData();
}
/**
* @description 综合筛选弹框
* @returns
*/
const toggleShowPopup = () => { const toggleShowPopup = () => {
updateState({ isShowFilterPopup: !isShowFilterPopup }); updateState({ isShowFilterPopup: !isShowFilterPopup });
}; };
@@ -164,9 +175,10 @@ const ListPage = () => {
}; };
return ( return (
<View> <View ref={scrollContextRef}>
{/* 自定义导航 */} {/* 自定义导航 */}
<CustomerNavBar /> <CustomerNavBar />
{/* <ShareCardCanvas /> */} {/* <ShareCardCanvas /> */}
<View className={styles.listPage}> <View className={styles.listPage}>
<View <View
@@ -187,7 +199,7 @@ const ListPage = () => {
<FilterPopup <FilterPopup
loading={loading} loading={loading}
onCancel={toggleShowPopup} onCancel={toggleShowPopup}
onConfirm={toggleShowPopup} onConfirm={handleFilterConfirm}
onChange={handleUpdateFilterOptions} onChange={handleUpdateFilterOptions}
filterOptions={filterOptions} filterOptions={filterOptions}
onClear={clearFilterOptions} onClear={clearFilterOptions}
@@ -199,7 +211,10 @@ const ListPage = () => {
)} )}
</View> </View>
{/* 筛选 */} {/* 筛选 */}
<View className={styles.listTopFilterWrapper}> <View className={styles.listTopFilterWrapper}
style={{
top: totalHeight -1,
}}>
<DistanceQuickFilter <DistanceQuickFilter
cityOptions={distanceData} cityOptions={distanceData}
quickOptions={quickFilterData} quickOptions={quickFilterData}
@@ -221,7 +236,6 @@ const ListPage = () => {
loadMoreMatches={loadMoreMatches} loadMoreMatches={loadMoreMatches}
/> />
</View> </View>
<GuideBar currentPage="list" /> <GuideBar currentPage="list" />
</View> </View>
); );

View File

@@ -38,16 +38,9 @@ const SearchResult = () => {
const pages = Taro.getCurrentPages() const pages = Taro.getCurrentPages()
const currentPage = pages?.[pages.length - 1]; const currentPage = pages?.[pages.length - 1];
updateState({currentPage, isSearchResult: true}) updateState({currentPage, isSearchResult: true})
// if (location?.address) {
// 保存位置
// updateState({ location });
// 页面加载时获取数据
console.log('===搜索结果页===')
getMatchesData(); getMatchesData();
// }
return () => { return () => {
console.log('===搜索结果组件卸载')
updateState({currentPage: '', isSearchResult: false}) updateState({currentPage: '', isSearchResult: false})
} }
}, []); }, []);

View File

@@ -46,6 +46,20 @@ export const getGamesIntegrateList = async (params?: Record<string, any>) => {
} }
}; };
/**
* 获取列表数量
* @param params
* @returns
*/
export const getGamesCount = async (params?: Record<string, any>) => {
try {
return httpService.post('/games/count', params, { showLoading: true })
} catch (error) {
console.error("列表数量获取失败:", error);
throw error;
}
};
/** /**
* 获取搜索历史记录的异步函数 * 获取搜索历史记录的异步函数
* @param {Object} params - 查询参数对象 * @param {Object} params - 查询参数对象

View File

@@ -6,6 +6,7 @@ import {
getSearchHistory, getSearchHistory,
clearHistory, clearHistory,
searchSuggestion, searchSuggestion,
getGamesCount,
} from "../services/listApi"; } from "../services/listApi";
import { import {
ListActions, ListActions,
@@ -14,12 +15,10 @@ import {
IPayload, IPayload,
} from "../../types/list/types"; } from "../../types/list/types";
import dateRangeUtils from '@/utils/dateRange'
// 完整的 Store 类型 // 完整的 Store 类型
type TennisStore = ListState & ListActions; type TennisStore = ListState & ListActions;
const toDate = dateRangeUtils?.formatDate(new Date())
const defaultDateRange: [string, string] = [dayjs().format('YYYY-MM-DD'), dayjs().add(1, 'M').format('YYYY-MM-DD')] const defaultDateRange: [string, string] = [dayjs().format('YYYY-MM-DD'), dayjs().add(1, 'M').format('YYYY-MM-DD')]
const defaultFilterOptions: IFilterOptions = { const defaultFilterOptions: IFilterOptions = {
@@ -100,6 +99,8 @@ export const useListStore = create<TennisStore>()((set, get) => ({
], ],
// 球局数量 // 球局数量
gamesNum: 0, gamesNum: 0,
// 是否还有更多数据
isHasMoreData: true,
// 页面滚动距离顶部距离 是否大于0 // 页面滚动距离顶部距离 是否大于0
isScrollTop: false, isScrollTop: false,
// 搜索历史数据 // 搜索历史数据
@@ -143,22 +144,31 @@ export const useListStore = create<TennisStore>()((set, get) => ({
lat: state?.location?.latitude, lat: state?.location?.latitude,
lng: state?.location?.longitude, lng: state?.location?.longitude,
}; };
console.log('===列表参数params', params)
return params; return params;
}, },
// 设置搜索的列表结果 // 设置搜索的列表结果
setListData: (payload: IPayload) => { setListData: (payload: IPayload & { isAppend?: boolean }) => {
const { isSearchResult } = get(); const { isSearchResult } = get();
const { error, data, loading, gamesNum } = payload; const { error, data, loading, count, isAppend = false } = payload;
const saveKey = isSearchResult ? "searchResultData" : "matches"; const saveKey = isSearchResult ? "searchResultData" : "matches";
const saveData = { error, loading, gamesNum, [saveKey]: data }; const isHasMoreData = count > 0;
console.log('===saveData', saveData)
set({...saveData}); if (isAppend) {
// 追加数据到现有数组
const currentData = get()[saveKey] || [];
const newData = [...currentData, ...(data || [])];
const saveData = { error, loading, count, isHasMoreData, [saveKey]: newData };
set({...saveData});
} else {
// 替换整个数组
const saveData = { error, loading, count, isHasMoreData, [saveKey]: data };
set({...saveData});
}
}, },
// 获取列表数据(常规搜索) // 获取列表数据(常规搜索)
fetchMatches: async (params, isFirstLoad = false) => { fetchMatches: async (params, isFirstLoad = false, isAppend = false) => {
set({ loading: true, error: null }); set({ loading: true, error: null });
const { getSearchParams, setListData, distanceQuickFilter } = get(); const { getSearchParams, setListData, distanceQuickFilter } = get();
@@ -191,70 +201,45 @@ export const useListStore = create<TennisStore>()((set, get) => ({
error: "-1", error: "-1",
data: [], data: [],
loading: false, loading: false,
gamesNum: 0, count: 0,
isAppend,
}); });
return Promise.reject(new Error('获取数据失败'));
} }
const { count, rows } = data; const { count, rows } = data;
setListData({ setListData({
error: '', error: '',
data: rows || [], data: rows || [],
loading: false, loading: false,
gamesNum: count, count,
isAppend,
}); });
return Promise.resolve();
} catch (error) { } catch (error) {
setListData({ setListData({
error: "-1", error: "-1",
data: [], data: [],
loading: false, loading: false,
gamesNum: 0, count: 0,
isAppend,
}); });
return Promise.reject(error);
} }
}, },
// 获取列表数据(智能筛选)
// getIntegrateListData: async (params) => {
// set({ loading: true, error: null });
// const { getSearchParams, setListData } = get();
// try {
// const searchParams = getSearchParams() || {};
// const reqParams = {
// ...(searchParams || {}),
// ...params,
// };
// reqParams.order = "";
// console.log("===getGamesIntegrateList 获取列表数据参数:", reqParams);
// const resData = (await getGamesIntegrateList(reqParams)) || {};
// const { data = {}, code } = resData;
// if (code !== 0) {
// setListData({
// error: '-1',
// data: [],
// loading: false,
// gamesNum: 0,
// });
// }
// const { count, rows } = data;
// setListData({
// // recommendList: rows || [],
// error: null,
// data: rows || [],
// loading: false,
// gamesNum: count,
// });
// } catch (error) {
// setListData({
// error: null,
// matches: [],
// loading: false,
// gamesNum: 0,
// });
// }
// },
// 获取列表数据 // 获取列表数据
getMatchesData: () => { getMatchesData: async () => {
const { fetchMatches } = get(); const { fetchMatches } = get();
fetchMatches({}, true); // 第一次进入页面,传入 isFirstLoad = true return await fetchMatches({}, true); // 第一次进入页面,传入 isFirstLoad = true
},
// 获取球局数量
fetchGetGamesCount: async () => {
const { getSearchParams } = get();
const params = getSearchParams() || {};
const resData = (await getGamesCount(params)) || {};
const gamesNum = resData?.data?.count || 0;
set({ gamesNum });
}, },
// 获取历史搜索数据 // 获取历史搜索数据
@@ -307,7 +292,7 @@ export const useListStore = create<TennisStore>()((set, get) => ({
// 更新综合筛选项 // 更新综合筛选项
updateFilterOptions: (payload: Record<string, any>) => { updateFilterOptions: (payload: Record<string, any>) => {
const { filterOptions: preFilterOptions, getMatchesData } = get() || {}; const { filterOptions: preFilterOptions, fetchGetGamesCount } = get() || {};
const filterOptions = { ...preFilterOptions, ...payload }; const filterOptions = { ...preFilterOptions, ...payload };
const filterCount = Object.values(filterOptions).filter(Boolean).length; const filterCount = Object.values(filterOptions).filter(Boolean).length;
console.log("===更新综合筛选项", filterOptions, filterCount); console.log("===更新综合筛选项", filterOptions, filterCount);
@@ -316,42 +301,48 @@ export const useListStore = create<TennisStore>()((set, get) => ({
filterCount, filterCount,
pageOption: defaultPageOption, pageOption: defaultPageOption,
}); });
// 重新搜索数据 // 获取球局数量
getMatchesData(); fetchGetGamesCount();
}, },
// 清空综合筛选选项 // 清空综合筛选选项
clearFilterOptions: () => { clearFilterOptions: () => {
const { getMatchesData } = get() || {}; const { getMatchesData, fetchGetGamesCount } = get() || {};
set({ set({
filterOptions: defaultFilterOptions, filterOptions: defaultFilterOptions,
filterCount: 0, filterCount: 0,
pageOption: defaultPageOption, pageOption: defaultPageOption,
}); });
getMatchesData(); getMatchesData();
fetchGetGamesCount();
}, },
// 加载更多数据 // 加载更多数据
loadMoreMatches: () => { loadMoreMatches: () => {
const { pageOption, getMatchesData } = get() || {}; const { pageOption, fetchMatches, isHasMoreData } = get() || {};
if (!isHasMoreData) {
return;
}
set({ set({
pageOption: { pageOption: {
page: pageOption?.page + 1, page: pageOption?.page + 1,
pageSize: 20, pageSize: 20,
}, },
}); });
getMatchesData(); // 加载更多时追加数据到现有数组
fetchMatches({}, false, true);
}, },
// 初始化搜索条件 重新搜索 // 初始化搜索条件 重新搜索
initialFilterSearch: () => { initialFilterSearch: async () => {
const { getMatchesData } = get(); const { getMatchesData, fetchGetGamesCount } = get();
set({ set({
distanceQuickFilter: defaultDistanceQuickFilter, distanceQuickFilter: defaultDistanceQuickFilter,
filterOptions: defaultFilterOptions, filterOptions: defaultFilterOptions,
pageOption: defaultPageOption, pageOption: defaultPageOption,
}); });
getMatchesData(); fetchGetGamesCount();
return await getMatchesData();
}, },
// 更新store数据 // 更新store数据

View File

@@ -45,6 +45,7 @@ export interface ListState {
timeBubbleData: BubbleOption[] timeBubbleData: BubbleOption[]
dateRangeOptions: BubbleOption[] dateRangeOptions: BubbleOption[]
gamesNum: number gamesNum: number
isHasMoreData: boolean
isScrollTop: boolean isScrollTop: boolean
searchHistoryParams: Record<string, any> searchHistoryParams: Record<string, any>
searchHistory: {id: number, title: string}[] searchHistory: {id: number, title: string}[]
@@ -61,7 +62,7 @@ export interface ListState {
} }
export interface ListActions { export interface ListActions {
fetchMatches: (params?: Record<string, any>,isFirstLoad?: Boolean) => Promise<void> fetchMatches: (params?: Record<string, any>, isFirstLoad?: Boolean, isAppend?: boolean) => Promise<void>
// getIntegrateListData: (params?: Record<string, any>) => Promise<void> // getIntegrateListData: (params?: Record<string, any>) => Promise<void>
getMatchesData: () => void getMatchesData: () => void
clearError: () => void clearError: () => void
@@ -75,13 +76,15 @@ export interface ListActions {
loadMoreMatches: () => void loadMoreMatches: () => void
initialFilterSearch: () => void initialFilterSearch: () => void
setListData: (payload: IPayload) => void setListData: (payload: IPayload) => void
fetchGetGamesCount: () => Promise<void>
} }
export interface IPayload { export interface IPayload {
error: string; error: string;
data: TennisMatch[]; data: TennisMatch[];
loading: boolean; loading: boolean;
gamesNum: number; count: number;
isAppend?: boolean;
} }
// 快捷筛选 // 快捷筛选
@@ -178,4 +181,15 @@ export interface ListCardProps {
shinei: string; shinei: string;
showSkeleton?: boolean; showSkeleton?: boolean;
key?: string key?: string
participants: {
user: {
avatar_url: string;
};
}[];
venue_image_list: {
url: string;
}[];
venue_description: string;
game_type: string;
type: string;
} }