1
This commit is contained in:
@@ -148,4 +148,8 @@ src/
|
||||
|
||||
## License
|
||||
|
||||
MIT
|
||||
MIT
|
||||
|
||||
"appid": "wx915ecf6c01bea4ec",
|
||||
|
||||
"appid": "wx815b533167eb7b53",
|
||||
@@ -2,7 +2,8 @@
|
||||
"miniprogramRoot": "dist/",
|
||||
"projectname": "playBallTogether",
|
||||
"description": "playBallTogether",
|
||||
"appid": "wx915ecf6c01bea4ec",
|
||||
"appid": "wx815b533167eb7b53",
|
||||
|
||||
"setting": {
|
||||
"urlCheck": true,
|
||||
"es6": true,
|
||||
|
||||
@@ -116,7 +116,7 @@ const DistanceQuickFilterV2 = (props) => {
|
||||
// 延时一下
|
||||
await new Promise(resolve => setTimeout(resolve, 600));
|
||||
// 先清除缓存和 area,确保使用最新的用户信息
|
||||
await updateCache( ["中国", response.data.last_location_province]);
|
||||
await updateCache( [ response.data.last_location_province, response.data.last_location_city ]);
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -105,15 +105,15 @@ const HomeNavbar = (props: IProps) => {
|
||||
const userInfo = useUserInfo();
|
||||
// 使用用户详情接口中的 last_location 字段
|
||||
// USER_SELECTED_CITY 第二个值应该是省份/直辖市,不能是区
|
||||
const lastLocationProvince = (userInfo as any)?.last_location_province || "";
|
||||
const lastLocationCity = (userInfo as any)?.last_location_city || "";
|
||||
// 只使用省份/直辖市,不使用城市(城市可能是区)
|
||||
const detectedLocation = lastLocationProvince;
|
||||
const detectedLocation = lastLocationCity;
|
||||
|
||||
// 检查是否应该显示定位确认弹窗
|
||||
const should_show_location_dialog = (): boolean => {
|
||||
try {
|
||||
const current_time = Date.now();
|
||||
|
||||
|
||||
// 检查是否在2小时内切换过城市
|
||||
const city_change_time = (Taro as any).getStorageSync(CITY_CHANGE_TIME_KEY);
|
||||
if (city_change_time) {
|
||||
@@ -127,13 +127,13 @@ const HomeNavbar = (props: IProps) => {
|
||||
(Taro as any).removeStorageSync(CITY_CHANGE_TIME_KEY);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// 检查是否在2小时内已选择"继续浏览"
|
||||
const dismiss_time = (Taro as any).getStorageSync(LOCATION_DIALOG_DISMISS_TIME_KEY);
|
||||
if (!dismiss_time) {
|
||||
return true; // 没有记录,可以显示
|
||||
}
|
||||
|
||||
|
||||
const time_diff = current_time - dismiss_time;
|
||||
// 如果距离上次选择"继续浏览"已超过2小时,可以再次显示
|
||||
if (time_diff >= TWO_HOURS_MS) {
|
||||
@@ -141,7 +141,7 @@ const HomeNavbar = (props: IProps) => {
|
||||
(Taro as any).removeStorageSync(LOCATION_DIALOG_DISMISS_TIME_KEY);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
// 在2小时内,不显示弹窗
|
||||
console.log(`[HomeNavbar] 距离上次选择"继续浏览"还不到2小时,剩余时间: ${Math.ceil((TWO_HOURS_MS - time_diff) / 1000 / 60)}分钟`);
|
||||
return false;
|
||||
@@ -158,7 +158,7 @@ const HomeNavbar = (props: IProps) => {
|
||||
console.log('[HomeNavbar] 用户在2小时内已选择"继续浏览"或切换过城市,不显示弹窗');
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
console.log('[HomeNavbar] 准备显示定位确认弹窗,隐藏 GuideBar');
|
||||
setLocationDialogData({ detectedProvince: detectedLocation, cachedCity });
|
||||
setLocationDialogVisible(true);
|
||||
@@ -172,13 +172,13 @@ const HomeNavbar = (props: IProps) => {
|
||||
useEffect(() => {
|
||||
// 1. 优先尝试从缓存中读取上次的定位信息
|
||||
const cachedCity = (Taro as any).getStorageSync(CITY_CACHE_KEY);
|
||||
|
||||
|
||||
if (cachedCity && Array.isArray(cachedCity) && cachedCity.length === 2) {
|
||||
// 如果有缓存的定位信息,使用缓存
|
||||
const cachedCityArray = cachedCity as [string, string];
|
||||
console.log("[HomeNavbar] 使用缓存的定位城市:", cachedCityArray);
|
||||
updateArea(cachedCityArray);
|
||||
|
||||
|
||||
// 如果用户详情中有位置信息,且与缓存不一致,检查是否需要弹窗
|
||||
if (detectedLocation && cachedCityArray[1] !== detectedLocation) {
|
||||
// 检查时间缓存,如果没有或过期,则弹出选择框
|
||||
@@ -192,7 +192,7 @@ const HomeNavbar = (props: IProps) => {
|
||||
} else if (detectedLocation) {
|
||||
// 只有在完全没有缓存的情况下,才使用用户详情中的位置信息
|
||||
console.log("[HomeNavbar] 没有缓存,使用用户详情中的位置信息:", detectedLocation);
|
||||
const newArea: [string, string] = ["中国", detectedLocation];
|
||||
const newArea: [string, string] = [(userInfo as any)?.last_location_province || "", detectedLocation];
|
||||
updateArea(newArea);
|
||||
// 保存定位信息到缓存
|
||||
(Taro as any).setStorageSync(CITY_CACHE_KEY, newArea);
|
||||
@@ -263,10 +263,10 @@ const HomeNavbar = (props: IProps) => {
|
||||
// 处理定位弹窗确认
|
||||
const handleLocationDialogConfirm = () => {
|
||||
if (!locationDialogData) return;
|
||||
|
||||
|
||||
const { detectedProvince } = locationDialogData;
|
||||
// 用户选择"切换到",使用用户详情中的位置信息
|
||||
const newArea: [string, string] = ["中国", detectedProvince];
|
||||
const newArea: [string, string] = [(userInfo as any)?.last_location_province || "", detectedProvince];
|
||||
updateArea(newArea);
|
||||
// 更新缓存为新的定位信息
|
||||
(Taro as any).setStorageSync(CITY_CACHE_KEY, newArea);
|
||||
@@ -279,13 +279,13 @@ const HomeNavbar = (props: IProps) => {
|
||||
console.error('保存城市切换时间失败:', error);
|
||||
}
|
||||
console.log("切换到用户详情中的位置信息并更新缓存:", detectedProvince);
|
||||
|
||||
|
||||
// 关闭弹窗
|
||||
setLocationDialogVisible(false);
|
||||
setLocationDialogData(null);
|
||||
// 关闭弹窗时显示 GuideBar
|
||||
setShowGuideBar(true);
|
||||
|
||||
|
||||
// 刷新数据
|
||||
handleCityChangeWithoutCache();
|
||||
};
|
||||
@@ -293,11 +293,11 @@ const HomeNavbar = (props: IProps) => {
|
||||
// 处理定位弹窗取消(用户选择"继续浏览")
|
||||
const handleLocationDialogCancel = () => {
|
||||
if (!locationDialogData) return;
|
||||
|
||||
|
||||
const { cachedCity } = locationDialogData;
|
||||
// 用户选择"继续浏览",保持缓存的定位城市
|
||||
console.log("保持缓存的定位城市:", cachedCity[1]);
|
||||
|
||||
|
||||
// 记录用户选择"继续浏览"的时间戳,2小时内不再提示
|
||||
try {
|
||||
const current_time = Date.now();
|
||||
@@ -306,7 +306,7 @@ const HomeNavbar = (props: IProps) => {
|
||||
} catch (error) {
|
||||
console.error('保存定位弹窗关闭时间失败:', error);
|
||||
}
|
||||
|
||||
|
||||
// 关闭弹窗
|
||||
setLocationDialogVisible(false);
|
||||
setLocationDialogData(null);
|
||||
@@ -321,7 +321,7 @@ const HomeNavbar = (props: IProps) => {
|
||||
if (cityPopupVisible) {
|
||||
setCityPopupVisible(false);
|
||||
}
|
||||
|
||||
|
||||
const currentPagePath = getCurrentFullPath();
|
||||
if (currentPagePath === "/game_pages/searchResult/index") {
|
||||
(Taro as any).navigateBack();
|
||||
@@ -338,7 +338,7 @@ const HomeNavbar = (props: IProps) => {
|
||||
if (cityPopupVisible) {
|
||||
setCityPopupVisible(false);
|
||||
}
|
||||
|
||||
|
||||
// 如果当前在列表页,点击后页面回到顶部
|
||||
if (getCurrentFullPath() === "/main_pages/index") {
|
||||
// 使用父组件传递的滚动方法(适配 ScrollView)
|
||||
@@ -363,7 +363,7 @@ const HomeNavbar = (props: IProps) => {
|
||||
if (cityPopupVisible) {
|
||||
setCityPopupVisible(false);
|
||||
}
|
||||
|
||||
|
||||
if (leftIconClick) {
|
||||
leftIconClick();
|
||||
} else {
|
||||
@@ -397,10 +397,10 @@ const HomeNavbar = (props: IProps) => {
|
||||
const handleCityChange = async (_newArea: any) => {
|
||||
// 用户手动选择的城市保存到缓存
|
||||
console.log("用户手动选择城市,更新缓存:", _newArea);
|
||||
|
||||
|
||||
// 先更新 area 状态(用于界面显示和接口参数)
|
||||
updateArea(_newArea);
|
||||
|
||||
|
||||
// 保存城市到缓存
|
||||
try {
|
||||
(Taro as any).setStorageSync(CITY_CACHE_KEY, _newArea);
|
||||
@@ -411,7 +411,7 @@ const HomeNavbar = (props: IProps) => {
|
||||
} catch (error) {
|
||||
console.error("保存城市缓存失败:", error);
|
||||
}
|
||||
|
||||
|
||||
// 先调用列表接口(会使用更新后的 state.area)
|
||||
if (refreshBothLists) {
|
||||
await refreshBothLists();
|
||||
@@ -481,9 +481,8 @@ const HomeNavbar = (props: IProps) => {
|
||||
{/* 搜索导航 */}
|
||||
{!showTitle && (
|
||||
<View
|
||||
className={`inputCustomerNavbarContainer toggleElement secondElement hidden ${
|
||||
showInput && "visible"
|
||||
} ${showInput ? "inputCustomerNavbarShowInput" : ""}`}
|
||||
className={`inputCustomerNavbarContainer toggleElement secondElement hidden ${showInput && "visible"
|
||||
} ${showInput ? "inputCustomerNavbarShowInput" : ""}`}
|
||||
style={navbarStyle}
|
||||
>
|
||||
<View className="navContent">
|
||||
|
||||
@@ -66,6 +66,8 @@ const ListPageContent: React.FC<ListPageContentProps> = ({
|
||||
gamesNum, // 新增:获取球局数量
|
||||
} = store;
|
||||
|
||||
const supportedCitiesList = useDictionaryStore((s) => s.getDictionaryValue('supported_cities', ['上海市'])) || [];
|
||||
|
||||
const {
|
||||
isShowFilterPopup,
|
||||
data: matches,
|
||||
@@ -92,6 +94,8 @@ const ListPageContent: React.FC<ListPageContentProps> = ({
|
||||
// 记录上一次加载数据时的城市,用于检测城市变化
|
||||
const lastLoadedAreaRef = useRef<[string, string] | null>(null);
|
||||
const prevIsActiveRef = useRef(isActive);
|
||||
// 记录是否是进入列表页的第一次调用 updateUserLocation(首次传 force: true)
|
||||
const hasUpdatedLocationRef = useRef(false);
|
||||
|
||||
// 处理距离筛选显示/隐藏
|
||||
const handleDistanceFilterVisibleChange = useCallback(
|
||||
@@ -364,7 +368,10 @@ const ListPageContent: React.FC<ListPageContentProps> = ({
|
||||
updateState({ location });
|
||||
if (location && location.latitude && location.longitude) {
|
||||
try {
|
||||
await updateUserLocation(location.latitude, location.longitude);
|
||||
// 进入列表页的第一次调用传 force: true,后续调用传 false
|
||||
const isFirstCall = !hasUpdatedLocationRef.current;
|
||||
await updateUserLocation(location.latitude, location.longitude, isFirstCall);
|
||||
hasUpdatedLocationRef.current = true;
|
||||
} catch (error) {
|
||||
console.error("更新用户位置失败:", error);
|
||||
}
|
||||
@@ -476,7 +483,7 @@ const ListPageContent: React.FC<ListPageContentProps> = ({
|
||||
initDictionaryData();
|
||||
}, []);
|
||||
|
||||
// 获取省份名称(area 格式: ["中国", "省份"])
|
||||
|
||||
const province = area?.at(1) || "上海";
|
||||
|
||||
function renderCityQrcode() {
|
||||
@@ -518,8 +525,12 @@ const ListPageContent: React.FC<ListPageContentProps> = ({
|
||||
}
|
||||
|
||||
// 判定是否显示"暂无球局"页面
|
||||
// 条件:省份不是上海 或 (已加载完成且球局数量为0)
|
||||
const shouldShowNoGames = province !== "上海市";
|
||||
// 从配置接口 /parameter/many_key 获取 supported_cities(格式如 "上海市||北京市")
|
||||
// 当前省份在有球局城市列表中则显示列表,否则显示暂无球局
|
||||
const shouldShowNoGames =
|
||||
supportedCitiesList.length > 0
|
||||
? !supportedCitiesList.includes(province)
|
||||
: province !== "上海市"; // 配置未加载时默认按上海判断
|
||||
|
||||
return (
|
||||
<>
|
||||
|
||||
@@ -134,7 +134,7 @@ export const getCityQrCode = async () => {
|
||||
}
|
||||
|
||||
// 获取行政区列表
|
||||
export const getDistricts = async (params: { country: string; state: string }) => {
|
||||
export const getDistricts = async (params: { province: string; city: string }) => {
|
||||
try {
|
||||
// 调用HTTP服务获取行政区列表
|
||||
return httpService.post('/cities/cities', params)
|
||||
|
||||
@@ -36,14 +36,17 @@ export const useDictionaryStore = create<DictionaryState>()((set, get) => ({
|
||||
set({ isLoading: true, error: null })
|
||||
|
||||
try {
|
||||
const keys = 'publishing_requirements,court_type,court_surface,supplementary_information,game_play,fabu_tip';
|
||||
const keys = 'publishing_requirements,court_type,court_surface,supplementary_information,game_play,fabu_tip,supported_cities';
|
||||
const response = await commonApi.getDictionaryManyKey(keys)
|
||||
|
||||
if (response.code === 0 && response.data) {
|
||||
const dictionaryData = {};
|
||||
keys.split(',').forEach(key => {
|
||||
const list = response.data[key];
|
||||
const listData = list.split('|');
|
||||
// supported_cities 格式如 "上海市||北京市",用 || 分割
|
||||
const listData = key === 'supported_cities'
|
||||
? (list ? String(list).split('||').map((s) => s.trim()).filter(Boolean) : [])
|
||||
: (list ? list.split('|') : []);
|
||||
dictionaryData[key] = listData;
|
||||
})
|
||||
set({
|
||||
|
||||
@@ -44,16 +44,16 @@ function translateCityData(dataTree) {
|
||||
return dataTree.map((item) => {
|
||||
const { children, ...rest } = item;
|
||||
// 只保留两级:国家和省份,去掉第三级(区域)
|
||||
const processedChildren = children?.length > 0
|
||||
const processedChildren = children?.length > 0
|
||||
? children.map(child => ({
|
||||
...child,
|
||||
text: child.name,
|
||||
label: child.name,
|
||||
value: child.name,
|
||||
children: null, // 去掉第三级
|
||||
}))
|
||||
...child,
|
||||
text: child.name,
|
||||
label: child.name,
|
||||
value: child.name,
|
||||
children: null, // 去掉第三级
|
||||
}))
|
||||
: null;
|
||||
|
||||
|
||||
return {
|
||||
...rest,
|
||||
text: rest.name,
|
||||
@@ -214,20 +214,19 @@ export const useListStore = create<TennisStore>()((set, get) => ({
|
||||
// 全城和快捷筛选
|
||||
const distanceQuickFilter = currentPageState?.distanceQuickFilter || {};
|
||||
const { distanceFilter, order, district } = distanceQuickFilter || {};
|
||||
|
||||
|
||||
// 始终使用 state.area,确保所有接口使用一致的城市参数
|
||||
const areaProvince = state.area?.at(1) || "";
|
||||
const areaProvince = state.area?.at(0) || "";
|
||||
const areaCity = state.area?.at(1) || "";
|
||||
const last_location_province = areaProvince;
|
||||
|
||||
// city 参数逻辑:
|
||||
// 1. 如果选择了行政区(district 有值),使用行政区的名称(label)
|
||||
// 2. 如果是"全城"(distanceFilter 为空),不传 city
|
||||
let city: string | undefined = undefined;
|
||||
|
||||
|
||||
let county: string | undefined = undefined;
|
||||
if (district) {
|
||||
// 从 districts 数组中查找对应的行政区名称
|
||||
const selectedDistrict = state.districts.find(item => item.value === district);
|
||||
if (selectedDistrict) {
|
||||
city = selectedDistrict.label; // 传递行政区名称,如"静安"
|
||||
county = selectedDistrict.label; // 传递行政区名称,如"静安"
|
||||
}
|
||||
}
|
||||
// 如果是"全城"(distanceFilter 为空),city 保持 undefined,不会被传递
|
||||
@@ -246,12 +245,13 @@ export const useListStore = create<TennisStore>()((set, get) => ({
|
||||
distanceFilter: distanceFilter,
|
||||
// 显式设置 province,确保始终使用 state.area 中的最新值
|
||||
province: last_location_province, // 始终使用 state.area 中的 province,确保城市参数一致
|
||||
city: areaCity,
|
||||
};
|
||||
|
||||
// 只在有值时添加 city 参数
|
||||
if (city) {
|
||||
searchOption.city = city;
|
||||
}
|
||||
if (county) {
|
||||
searchOption.county = county;
|
||||
}
|
||||
|
||||
const params = {
|
||||
pageOption: currentPageState?.pageOption,
|
||||
@@ -374,7 +374,7 @@ export const useListStore = create<TennisStore>()((set, get) => ({
|
||||
|
||||
try {
|
||||
const searchParams = getSearchParams() || {};
|
||||
|
||||
|
||||
// 并发请求:常规列表、智能排序列表
|
||||
const [listResSettled, integrateResSettled] = await Promise.allSettled([
|
||||
getGamesList({
|
||||
@@ -447,7 +447,7 @@ export const useListStore = create<TennisStore>()((set, get) => ({
|
||||
const state = get();
|
||||
const { getSearchParams } = state;
|
||||
const searchParams = getSearchParams() || {};
|
||||
|
||||
|
||||
// 使用和 games/integrate_list 相同的参数构建逻辑
|
||||
const params = {
|
||||
...searchParams,
|
||||
@@ -457,7 +457,7 @@ export const useListStore = create<TennisStore>()((set, get) => ({
|
||||
isRefresh: true, // 和 integrate_list 保持一致
|
||||
},
|
||||
};
|
||||
|
||||
|
||||
console.log("fetchGetGamesCount 参数:", { area: state.area, params: JSON.stringify(params) });
|
||||
const resData = (await getGamesCount(params)) || {};
|
||||
const gamesNum = resData?.data?.count || 0;
|
||||
@@ -551,7 +551,7 @@ export const useListStore = create<TennisStore>()((set, get) => ({
|
||||
const state = get();
|
||||
const { currentPageState } = state.getCurrentPageState();
|
||||
const filterOptions = { ...currentPageState?.filterOptions, ...payload };
|
||||
|
||||
|
||||
// 计算筛选数量:排除 dateRange、ntrp 默认值,以及空数组和空字符串
|
||||
const filterCount = Object.entries(filterOptions).filter(([key, value]) => {
|
||||
if (key === 'dateRange') return false; // 日期区间不算筛选
|
||||
@@ -572,7 +572,7 @@ export const useListStore = create<TennisStore>()((set, get) => ({
|
||||
filterCount,
|
||||
pageOption: defaultPageOption,
|
||||
});
|
||||
|
||||
|
||||
// 使用 Promise.resolve 确保状态更新后再调用接口
|
||||
// 先调用列表接口,然后在列表接口完成后调用数量接口
|
||||
Promise.resolve().then(async () => {
|
||||
@@ -590,7 +590,7 @@ export const useListStore = create<TennisStore>()((set, get) => ({
|
||||
const { currentPageState } = state.getCurrentPageState();
|
||||
const { distanceQuickFilter } = currentPageState || {};
|
||||
const newDistanceQuickFilter = { ...distanceQuickFilter, ...payload };
|
||||
|
||||
|
||||
// 先更新状态
|
||||
state.updateCurrentPageState({
|
||||
distanceQuickFilter: newDistanceQuickFilter,
|
||||
@@ -729,15 +729,15 @@ export const useListStore = create<TennisStore>()((set, get) => ({
|
||||
async getDistricts() {
|
||||
try {
|
||||
const state = get();
|
||||
// 从 area 中获取省份,area 格式: ["中国", 省份, 城市]
|
||||
const country = "中国";
|
||||
// 从 area 中获取省份,area 格式: [ 省份, 城市]
|
||||
const province = state.area?.at(0) || "上海";
|
||||
const cn_city = state.area?.at(1) || "上海市"; // area[1] 是省份
|
||||
|
||||
const res = await getDistricts({
|
||||
country,
|
||||
state: cn_city
|
||||
|
||||
const res = await getDistricts({
|
||||
province,
|
||||
city: cn_city
|
||||
});
|
||||
|
||||
|
||||
if (res.code === 0 && res.data) {
|
||||
const districts = res.data.map((item) => ({
|
||||
label: item.cn_county,
|
||||
|
||||
@@ -48,10 +48,10 @@ export const useUser = create<UserState>()((set) => ({
|
||||
|
||||
// 优先使用缓存中的城市,不使用用户信息中的位置
|
||||
// 检查是否有缓存的城市
|
||||
|
||||
|
||||
const cachedCity = (Taro as any).getStorageSync?.(CITY_CACHE_KEY);
|
||||
|
||||
|
||||
|
||||
|
||||
if (cachedCity && Array.isArray(cachedCity) && cachedCity.length === 2) {
|
||||
// 如果有缓存的城市,使用缓存,不更新 area
|
||||
@@ -63,10 +63,10 @@ export const useUser = create<UserState>()((set) => ({
|
||||
if (userData?.last_location_province) {
|
||||
const listStore = useListStore.getState();
|
||||
const currentArea = listStore.area;
|
||||
|
||||
|
||||
// 只有当 area 不存在时才使用用户信息中的位置
|
||||
if (!currentArea) {
|
||||
const newArea: [string, string] = ["中国", userData.last_location_province];
|
||||
const newArea: [string, string] = [userData.last_location_province||"", userData.last_location_city||""];
|
||||
listStore.updateArea(newArea);
|
||||
// 保存到缓存
|
||||
useUser.getState().updateCache(newArea);
|
||||
@@ -103,7 +103,7 @@ export const useUser = create<UserState>()((set) => ({
|
||||
const currentArea = listStore.area;
|
||||
// 只有当 area 不存在或与 userLastLocationProvince 不一致时才更新
|
||||
if (!currentArea || currentArea[1] !== userInfo.last_location_province) {
|
||||
const newArea: [string, string] = ["中国", userInfo.last_location_province];
|
||||
const newArea: [string, string] = [userInfo.last_location_province || "", userInfo.last_location_city || ""];
|
||||
listStore.updateArea(newArea);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user