304 lines
8.1 KiB
TypeScript
304 lines
8.1 KiB
TypeScript
import SearchBar from "@/components/SearchBar";
|
|
import FilterPopup from "@/components/FilterPopup";
|
|
import styles from "./index.module.scss";
|
|
import { useEffect, useRef, useCallback } from "react";
|
|
import Taro, { usePageScroll } from "@tarojs/taro";
|
|
import { useListStore } from "@/store/listStore";
|
|
import { useGlobalState } from "@/store/global";
|
|
import { View } from "@tarojs/components";
|
|
import CustomerNavBar from "@/container/listCustomNavbar";
|
|
import GuideBar from "@/components/GuideBar";
|
|
import ListContainer from "@/container/listContainer";
|
|
import DistanceQuickFilter from "@/components/DistanceQuickFilter";
|
|
import { withAuth } from "@/components";
|
|
import { updateUserLocation } from "@/services/userService";
|
|
|
|
const ListPage = () => {
|
|
|
|
// 从 store 获取数据和方法
|
|
const store = useListStore() || {};
|
|
|
|
const { statusNavbarHeightInfo, getCurrentLocationInfo } = useGlobalState() || {};
|
|
|
|
const { totalHeight } = statusNavbarHeightInfo || {};
|
|
const {
|
|
listPageState,
|
|
loading,
|
|
error,
|
|
searchValue,
|
|
distanceData,
|
|
quickFilterData,
|
|
getMatchesData,
|
|
updateState,
|
|
updateListPageState,
|
|
updateFilterOptions, // 更新筛选条件
|
|
clearFilterOptions,
|
|
initialFilterSearch,
|
|
loadMoreMatches,
|
|
fetchGetGamesCount,
|
|
updateDistanceQuickFilter,
|
|
} = store;
|
|
|
|
const {
|
|
isShowFilterPopup,
|
|
data: matches,
|
|
recommendList,
|
|
filterCount,
|
|
filterOptions,
|
|
distanceQuickFilter,
|
|
isShowInputCustomerNavBar,
|
|
pageOption
|
|
} = listPageState || {};
|
|
|
|
// 防抖的滚动处理函数
|
|
const handleScroll = useCallback((res) => {
|
|
const currentScrollTop = res?.scrollTop || 0;
|
|
|
|
// 添加缓冲区,避免临界点频繁切换
|
|
const buffer = 10; // 10px 缓冲区
|
|
const shouldShowInputNav = currentScrollTop >= (totalHeight + buffer);
|
|
const shouldHideInputNav = currentScrollTop < (totalHeight - buffer);
|
|
|
|
// 清除之前的定时器
|
|
if (scrollTimeoutRef.current) {
|
|
clearTimeout(scrollTimeoutRef.current);
|
|
}
|
|
|
|
// 防抖处理,避免频繁更新状态
|
|
scrollTimeoutRef.current = setTimeout(() => {
|
|
// 只有在状态真正需要改变时才更新
|
|
if (shouldShowInputNav && !isShowInputCustomerNavBar) {
|
|
updateListPageState({
|
|
isShowInputCustomerNavBar: true
|
|
});
|
|
} else if (shouldHideInputNav && isShowInputCustomerNavBar) {
|
|
updateListPageState({
|
|
isShowInputCustomerNavBar: false
|
|
});
|
|
}
|
|
|
|
lastScrollTopRef.current = currentScrollTop;
|
|
}, 16); // 约60fps的防抖间隔
|
|
}, [totalHeight, isShowInputCustomerNavBar, updateState]);
|
|
|
|
usePageScroll(handleScroll);
|
|
|
|
const scrollContextRef = useRef(null)
|
|
const scrollTimeoutRef = useRef<NodeJS.Timeout | null>(null)
|
|
const lastScrollTopRef = useRef(0)
|
|
|
|
useEffect(() => {
|
|
getLocation()
|
|
}, []);
|
|
|
|
// 监听数据变化,如果是第一页就滚动到顶部
|
|
useEffect(() => {
|
|
if (pageOption?.page === 1 && matches?.length > 0) {
|
|
Taro.pageScrollTo({
|
|
scrollTop: 0,
|
|
duration: 300
|
|
});
|
|
}
|
|
}, [matches, pageOption?.page]);
|
|
|
|
// 清理定时器
|
|
useEffect(() => {
|
|
return () => {
|
|
if (scrollTimeoutRef.current) {
|
|
clearTimeout(scrollTimeoutRef.current);
|
|
}
|
|
};
|
|
}, []);
|
|
|
|
|
|
// 监听距离和排序方式变化,自动调用接口
|
|
// useEffect(() => {
|
|
// // 只有当 distanceQuickFilter 有值时才调用接口
|
|
// if (distanceQuickFilter?.distanceFilter !== undefined || distanceQuickFilter?.order !== undefined) {
|
|
|
|
// // if (distanceQuickFilter?.quick !== "0") {
|
|
// getMatchesData();
|
|
// // }
|
|
// }
|
|
// }, [distanceQuickFilter?.distanceFilter, distanceQuickFilter?.order]);
|
|
|
|
// 获取位置信息
|
|
const getLocation = async () => {
|
|
const location = await getCurrentLocationInfo()
|
|
|
|
// 保存位置到全局状态
|
|
updateState({ location });
|
|
|
|
// 同时更新用户位置到后端和 store
|
|
if (location && location.latitude && location.longitude) {
|
|
try {
|
|
await updateUserLocation(location.latitude, location.longitude);
|
|
} catch (error) {
|
|
console.error('更新用户位置失败:', error);
|
|
}
|
|
}
|
|
fetchGetGamesCount();
|
|
|
|
// 页面加载时获取数据
|
|
getMatchesData();
|
|
return location;
|
|
}
|
|
|
|
const refreshMatches = () => {
|
|
initialFilterSearch(true);
|
|
};
|
|
|
|
// const getLoadMoreMatches = () => {
|
|
// loadMoreMatches()
|
|
// }
|
|
|
|
// 下拉刷新处理函数 - 使用Taro生命周期钩子
|
|
Taro.usePullDownRefresh(async () => {
|
|
try {
|
|
// 调用刷新方法
|
|
await refreshMatches();
|
|
|
|
// 刷新完成后停止下拉刷新动画
|
|
Taro.stopPullDownRefresh();
|
|
|
|
// 显示刷新成功提示
|
|
Taro.showToast({
|
|
title: "刷新成功",
|
|
icon: "success",
|
|
duration: 1000,
|
|
});
|
|
} catch (error) {
|
|
// 刷新失败时也停止动画
|
|
Taro.stopPullDownRefresh();
|
|
|
|
Taro.showToast({
|
|
title: "刷新失败,请重试",
|
|
icon: "error",
|
|
duration: 1000,
|
|
});
|
|
}
|
|
});
|
|
|
|
/**
|
|
* @description 综合筛选确认
|
|
* @returns
|
|
*/
|
|
const handleFilterConfirm = () => {
|
|
toggleShowPopup();
|
|
getMatchesData();
|
|
}
|
|
|
|
/**
|
|
* @description 综合筛选弹框
|
|
* @returns
|
|
*/
|
|
const toggleShowPopup = () => {
|
|
updateListPageState({
|
|
isShowFilterPopup: !isShowFilterPopup
|
|
});
|
|
};
|
|
|
|
/**
|
|
* @description 更新筛选条件
|
|
* @param {Record<string, any>} params 筛选项
|
|
*/
|
|
const handleUpdateFilterOptions = (params: Record<string, any>) => {
|
|
updateFilterOptions(params);
|
|
};
|
|
|
|
const handleSearchChange = () => { };
|
|
|
|
// 距离筛选
|
|
const handleDistanceOrQuickChange = (name, value) => {
|
|
updateDistanceQuickFilter({
|
|
[name]: value,
|
|
});
|
|
// updateListPageState({
|
|
// distanceQuickFilter: {
|
|
// ...distanceQuickFilter,
|
|
// [name]: value,
|
|
// },
|
|
// });
|
|
};
|
|
|
|
const handleSearchClick = () => {
|
|
Taro.navigateTo({
|
|
url: "/game_pages/search/index",
|
|
});
|
|
};
|
|
|
|
return (
|
|
<>
|
|
{/* 自定义导航 */}
|
|
<CustomerNavBar
|
|
config={{
|
|
showInput: isShowInputCustomerNavBar,
|
|
}}
|
|
/>
|
|
<View ref={scrollContextRef}>
|
|
{/* <ShareCardCanvas /> */}
|
|
{/* 列表内容 */}
|
|
<View className={styles.listPage} style={{ paddingTop: totalHeight }}>
|
|
{/* 综合筛选 */}
|
|
{isShowFilterPopup && (
|
|
<View>
|
|
<FilterPopup
|
|
loading={loading}
|
|
onCancel={toggleShowPopup}
|
|
onConfirm={handleFilterConfirm}
|
|
onChange={handleUpdateFilterOptions}
|
|
filterOptions={filterOptions}
|
|
onClear={clearFilterOptions}
|
|
visible={isShowFilterPopup}
|
|
onClose={toggleShowPopup}
|
|
statusNavbarHeigh={statusNavbarHeightInfo?.totalHeight}
|
|
/>
|
|
</View>
|
|
)}
|
|
<View
|
|
className={`${styles.listTopSearchWrapper}`}
|
|
>
|
|
<SearchBar
|
|
handleFilterIcon={toggleShowPopup}
|
|
isSelect={filterCount > 0}
|
|
filterCount={filterCount}
|
|
onChange={handleSearchChange}
|
|
value={searchValue}
|
|
onInputClick={handleSearchClick}
|
|
/>
|
|
|
|
</View>
|
|
{/* 筛选 */}
|
|
<View className={styles.listTopFilterWrapper}
|
|
style={{
|
|
top: totalHeight - 1,
|
|
}}>
|
|
<DistanceQuickFilter
|
|
cityOptions={distanceData}
|
|
quickOptions={quickFilterData}
|
|
onChange={handleDistanceOrQuickChange}
|
|
cityName="distanceFilter"
|
|
quickName="order"
|
|
cityValue={distanceQuickFilter?.distanceFilter}
|
|
quickValue={distanceQuickFilter?.order}
|
|
/>
|
|
</View>
|
|
|
|
{/* 列表内容 */}
|
|
<ListContainer
|
|
data={matches}
|
|
recommendList={recommendList}
|
|
loading={loading}
|
|
error={error}
|
|
reload={refreshMatches}
|
|
loadMoreMatches={loadMoreMatches}
|
|
/>
|
|
</View>
|
|
</View>
|
|
<GuideBar currentPage="list" />
|
|
</>
|
|
);
|
|
};
|
|
|
|
export default withAuth(ListPage);
|