diff --git a/src/components/HomeNavbar/index.tsx b/src/components/HomeNavbar/index.tsx index 920a90f..019eea6 100644 --- a/src/components/HomeNavbar/index.tsx +++ b/src/components/HomeNavbar/index.tsx @@ -1,4 +1,4 @@ -import { useEffect, useState, useRef } from "react"; +import { useEffect, useState } from "react"; import { View, Text, Image } from "@tarojs/components"; import img from "@/config/images"; import { useGlobalState } from "@/store/global"; @@ -96,7 +96,6 @@ const HomeNavbar = (props: IProps) => { detectedProvince: string; cachedCity: [string, string]; } | null>(null); - const hasShownLocationDialog = useRef(false); // 防止重复弹窗 // 监听城市选择器状态变化,通知父组件 useEffect(() => { @@ -110,44 +109,18 @@ const HomeNavbar = (props: IProps) => { // 只使用省份/直辖市,不使用城市(城市可能是区) const detectedLocation = lastLocationProvince; - // 初始化城市:优先使用缓存的定位信息,其次使用用户详情中的位置信息 - 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("使用缓存的定位城市:", cachedCityArray); - updateArea(cachedCityArray); - - // 如果用户详情中有位置信息且与缓存不同,弹窗询问是否切换 - if (detectedLocation && cachedCityArray[1] !== detectedLocation && !hasShownLocationDialog.current) { - hasShownLocationDialog.current = true; - showLocationConfirmDialog(detectedLocation, cachedCityArray); - } - } else if (detectedLocation) { - // 如果没有缓存但有用户详情中的位置信息,直接使用并保存到缓存 - console.log("没有缓存,使用用户详情中的位置信息:", detectedLocation); - const newArea: [string, string] = ["中国", detectedLocation]; - updateArea(newArea); - // 保存定位信息到缓存 - (Taro as any).setStorageSync(CITY_CACHE_KEY, newArea); - } - }, [detectedLocation]); - - // 检查是否在2小时内已选择"继续浏览"或切换过城市 + // 检查是否应该显示定位确认弹窗 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) { - const current_time = Date.now(); const time_diff = current_time - city_change_time; - // 如果距离上次切换城市还在2小时内,不显示弹窗 if (time_diff < TWO_HOURS_MS) { - console.log(`距离上次切换城市还不到2小时,剩余时间: ${Math.ceil((TWO_HOURS_MS - time_diff) / 1000 / 60)}分钟,不显示定位弹窗`); + console.log(`[HomeNavbar] 距离上次切换城市还不到2小时,剩余时间: ${Math.ceil((TWO_HOURS_MS - time_diff) / 1000 / 60)}分钟,不显示定位弹窗`); return false; } else { // 超过2小时,清除过期记录 @@ -161,9 +134,7 @@ const HomeNavbar = (props: IProps) => { return true; // 没有记录,可以显示 } - const current_time = Date.now(); const time_diff = current_time - dismiss_time; - // 如果距离上次选择"继续浏览"已超过2小时,可以再次显示 if (time_diff >= TWO_HOURS_MS) { // 清除过期记录 @@ -172,30 +143,123 @@ const HomeNavbar = (props: IProps) => { } // 在2小时内,不显示弹窗 - console.log(`距离上次选择"继续浏览"还不到2小时,剩余时间: ${Math.ceil((TWO_HOURS_MS - time_diff) / 1000 / 60)}分钟`); + console.log(`[HomeNavbar] 距离上次选择"继续浏览"还不到2小时,剩余时间: ${Math.ceil((TWO_HOURS_MS - time_diff) / 1000 / 60)}分钟`); return false; } catch (error) { - console.error('检查定位弹窗显示条件失败:', error); + console.error('[HomeNavbar] 检查定位弹窗显示条件失败:', error); return true; // 出错时默认显示 } }; // 显示定位确认弹窗 const showLocationConfirmDialog = (detectedLocation: string, cachedCity: [string, string]) => { - // 检查是否在2小时内已选择"继续浏览" + // 检查是否应该显示弹窗 if (!should_show_location_dialog()) { - console.log('[LocationDialog] 用户在2小时内已选择"继续浏览",不显示弹窗'); + console.log('[HomeNavbar] 用户在2小时内已选择"继续浏览"或切换过城市,不显示弹窗'); return; } - console.log('[LocationDialog] 准备显示定位确认弹窗,隐藏 GuideBar'); + console.log('[HomeNavbar] 准备显示定位确认弹窗,隐藏 GuideBar'); setLocationDialogData({ detectedProvince: detectedLocation, cachedCity }); setLocationDialogVisible(true); // 显示弹窗时隐藏 GuideBar setShowGuideBar(false); - console.log('[LocationDialog] setShowGuideBar(false) 已调用'); + console.log('[HomeNavbar] setShowGuideBar(false) 已调用'); }; + // 初始化城市:优先使用缓存的定位信息,如果缓存城市和用户详情位置不一致,且时间过期,则弹出选择框 + // 只在组件挂载时执行一次,避免重复执行 + 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) { + // 检查时间缓存,如果没有或过期,则弹出选择框 + if (should_show_location_dialog()) { + console.log("[HomeNavbar] 缓存城市与用户详情位置不一致,且时间过期,弹出选择框"); + showLocationConfirmDialog(detectedLocation, cachedCityArray); + } else { + console.log("[HomeNavbar] 缓存城市与用户详情位置不一致,但时间未过期,不弹出选择框"); + } + } + } else if (detectedLocation) { + // 只有在完全没有缓存的情况下,才使用用户详情中的位置信息 + console.log("[HomeNavbar] 没有缓存,使用用户详情中的位置信息:", detectedLocation); + const newArea: [string, string] = ["中国", detectedLocation]; + updateArea(newArea); + // 保存定位信息到缓存 + (Taro as any).setStorageSync(CITY_CACHE_KEY, newArea); + } + // eslint-disable-next-line react-hooks/exhaustive-deps + }, []); // 空依赖数组,确保只在组件挂载时执行一次 + + // 检查是否在2小时内已选择"继续浏览"或切换过城市(当前不使用,首页重新进入时直接使用缓存中的位置) + // const should_show_location_dialog = (): boolean => { + // try { + // // 检查是否在2小时内切换过城市 + // const city_change_time = (Taro as any).getStorageSync(CITY_CHANGE_TIME_KEY); + // if (city_change_time) { + // const current_time = Date.now(); + // const time_diff = current_time - city_change_time; + // + // // 如果距离上次切换城市还在2小时内,不显示弹窗 + // if (time_diff < TWO_HOURS_MS) { + // console.log(`距离上次切换城市还不到2小时,剩余时间: ${Math.ceil((TWO_HOURS_MS - time_diff) / 1000 / 60)}分钟,不显示定位弹窗`); + // return false; + // } else { + // // 超过2小时,清除过期记录 + // (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 current_time = Date.now(); + // const time_diff = current_time - dismiss_time; + // + // // 如果距离上次选择"继续浏览"已超过2小时,可以再次显示 + // if (time_diff >= TWO_HOURS_MS) { + // // 清除过期记录 + // (Taro as any).removeStorageSync(LOCATION_DIALOG_DISMISS_TIME_KEY); + // return true; + // } + // + // // 在2小时内,不显示弹窗 + // console.log(`距离上次选择"继续浏览"还不到2小时,剩余时间: ${Math.ceil((TWO_HOURS_MS - time_diff) / 1000 / 60)}分钟`); + // return false; + // } catch (error) { + // console.error('检查定位弹窗显示条件失败:', error); + // return true; // 出错时默认显示 + // } + // }; + + // 显示定位确认弹窗(当前不使用,首页重新进入时直接使用缓存中的位置) + // const showLocationConfirmDialog = (detectedLocation: string, cachedCity: [string, string]) => { + // // 检查是否在2小时内已选择"继续浏览" + // if (!should_show_location_dialog()) { + // console.log('[LocationDialog] 用户在2小时内已选择"继续浏览",不显示弹窗'); + // return; + // } + // + // console.log('[LocationDialog] 准备显示定位确认弹窗,隐藏 GuideBar'); + // setLocationDialogData({ detectedProvince: detectedLocation, cachedCity }); + // setLocationDialogVisible(true); + // // 显示弹窗时隐藏 GuideBar + // setShowGuideBar(false); + // console.log('[LocationDialog] setShowGuideBar(false) 已调用'); + // }; + // 处理定位弹窗确认 const handleLocationDialogConfirm = () => { if (!locationDialogData) return; @@ -206,6 +270,14 @@ const HomeNavbar = (props: IProps) => { updateArea(newArea); // 更新缓存为新的定位信息 (Taro as any).setStorageSync(CITY_CACHE_KEY, newArea); + // 记录切换城市的时间戳,2小时内不再提示 + try { + const current_time = Date.now(); + (Taro as any).setStorageSync(CITY_CHANGE_TIME_KEY, current_time); + console.log(`[LocationDialog] 已记录用户切换城市的时间,2小时内不再提示`); + } catch (error) { + console.error('保存城市切换时间失败:', error); + } console.log("切换到用户详情中的位置信息并更新缓存:", detectedProvince); // 关闭弹窗 diff --git a/src/main_pages/components/ListPageContent.tsx b/src/main_pages/components/ListPageContent.tsx index d6e3181..58703b4 100644 --- a/src/main_pages/components/ListPageContent.tsx +++ b/src/main_pages/components/ListPageContent.tsx @@ -129,15 +129,37 @@ const ListPageContent: React.FC = ({ // ScrollView 滚动处理 const handleScrollViewScroll = useCallback( (e: any) => { - - const currentScrollTop = e?.detail?.scrollTop || 0; + const scrollHeight = e?.detail?.scrollHeight || 0; + const clientHeight = e?.detail?.clientHeight || 0; const lastScrollTop = lastScrollTopRef.current; const currentTime = Date.now(); const timeDiff = currentTime - lastScrollTimeRef.current; if (timeDiff < 100) return; + // 计算距离底部的距离,提前加载(距离底部600px时开始加载) + // 注意:如果 scrollHeight 或 clientHeight 不可用,则使用 lowerThreshold 触发 + if (scrollHeight > 0 && clientHeight > 0) { + const distanceToBottom = scrollHeight - currentScrollTop - clientHeight; + const preloadThreshold = 600; // 提前加载阈值 + + // 如果距离底部小于阈值,且正在向下滚动,且有更多数据,则提前加载 + if ( + distanceToBottom < preloadThreshold && + distanceToBottom > 0 && + !loading && + !loadingMoreRef.current && + listPageState?.isHasMoreData && + currentScrollTop > lastScrollTop // 向下滚动 + ) { + loadingMoreRef.current = true; + loadMoreMatches().finally(() => { + loadingMoreRef.current = false; + }); + } + } + const scrollDiff = currentScrollTop - lastScrollTop; let newDirection = scrollDirectionRef.current; if (Math.abs(scrollDiff) > 15) { @@ -195,7 +217,7 @@ const ListPageContent: React.FC = ({ lastScrollTopRef.current = currentScrollTop; lastScrollTimeRef.current = currentTime; }, - [updateListPageState, onNavStateChange] + [updateListPageState, onNavStateChange, loading, loadMoreMatches, listPageState?.isHasMoreData] // 移除 showSearchBar 和 isShowInputCustomerNavBar 依赖,使用 ref 获取最新值 ); @@ -550,7 +572,7 @@ const ListPageContent: React.FC = ({ refresherEnabled={true} refresherTriggered={refreshing} onRefresherRefresh={handleRefresh} - lowerThreshold={100} + lowerThreshold={600} onScrollToLower={async () => { if ( !loading && diff --git a/src/store/userStore.ts b/src/store/userStore.ts index 5c22707..1b35edd 100644 --- a/src/store/userStore.ts +++ b/src/store/userStore.ts @@ -1,4 +1,5 @@ import { create } from "zustand"; +import Taro from "@tarojs/taro"; import { fetchUserProfile, updateUserProfile, @@ -44,14 +45,31 @@ export const useUser = create()((set) => ({ const userData = res.data; set({ user: userData }); - // 当 userLastLocationProvince 更新时,同步更新 area + // 优先使用缓存中的城市,不使用用户信息中的位置 + // 检查是否有缓存的城市 + const CITY_CACHE_KEY = "USER_SELECTED_CITY"; + const cachedCity = (Taro as any).getStorageSync?.(CITY_CACHE_KEY); + + if (cachedCity && Array.isArray(cachedCity) && cachedCity.length === 2) { + // 如果有缓存的城市,使用缓存,不更新 area + console.log("[userStore] 检测到缓存的城市,使用缓存,不更新 area"); + return userData; + } + + // 只有当没有缓存时,才使用用户信息中的位置 if (userData?.last_location_province) { const listStore = useListStore.getState(); const currentArea = listStore.area; - // 只有当 area 不存在或与 userLastLocationProvince 不一致时才更新 - if (!currentArea || currentArea[1] !== userData.last_location_province) { + // 只有当 area 不存在时才使用用户信息中的位置 + if (!currentArea) { const newArea: [string, string] = ["中国", userData.last_location_province]; listStore.updateArea(newArea); + // 保存到缓存 + try { + (Taro as any).setStorageSync?.(CITY_CACHE_KEY, newArea); + } catch (error) { + console.error("保存城市缓存失败:", error); + } } }