diff --git a/src/components/DistanceQuickFilterV2/index.scss b/src/components/DistanceQuickFilterV2/index.scss index eb926ee..e6342fb 100644 --- a/src/components/DistanceQuickFilterV2/index.scss +++ b/src/components/DistanceQuickFilterV2/index.scss @@ -85,6 +85,10 @@ font-size: 13px; font-weight: 400; color: #3c3c43; + display: flex; + flex-direction: row; + align-items: center; + gap:4px; } .distanceWrap { diff --git a/src/components/DistanceQuickFilterV2/index.tsx b/src/components/DistanceQuickFilterV2/index.tsx index 3411faf..2989a64 100644 --- a/src/components/DistanceQuickFilterV2/index.tsx +++ b/src/components/DistanceQuickFilterV2/index.tsx @@ -1,9 +1,14 @@ import { useRef, useState, useEffect } from "react"; import { Menu } from "@nutui/nutui-react-taro"; import { Image, View, ScrollView } from "@tarojs/components"; +import Taro from "@tarojs/taro"; import img from "@/config/images"; import Bubble from "../Bubble"; -import { useListState } from "@/store/listStore"; +import { useListState, useListStore } from "@/store/listStore"; +import { getCurrentLocation } from "@/utils/locationUtils"; +import { updateUserLocation } from "@/services/userService"; +import { useGlobalState } from "@/store/global"; +import { useUserActions } from "@/store/userStore"; import "./index.scss"; const DistanceQuickFilterV2 = (props) => { @@ -19,15 +24,19 @@ const DistanceQuickFilterV2 = (props) => { quickValue, districtValue, // 新增:行政区选中值 onMenuVisibleChange, // 菜单展开/收起回调 + onRelocate, // 重新定位回调 } = props; const cityRef = useRef(null); const quickRef = useRef(null); const [changePosition, setChangePosition] = useState([]); const [isMenuOpen, setIsMenuOpen] = useState(false); - const [keys, setKeys] = useState(0); + const [keys, setKeys] = useState(0); + const [isRelocating, setIsRelocating] = useState(false); // 从 store 获取当前城市信息 const { area } = useListState(); const currentCity = area?.at(-1) || ""; // 获取省份/城市名称 + const { updateState } = useGlobalState() || {}; + const { fetchUserInfo, updateCache } = useUserActions(); // 全城筛选显示的标题 - 如果选择了行政区,显示行政区名称 const getCityTitle = () => { @@ -79,6 +88,64 @@ const DistanceQuickFilterV2 = (props) => { index === 1 && (quickRef.current as any)?.toggle(false); }; + + // 重新获取当前位置,调用接口把位置传递后端 + const handleRelocate = async () => { + if (isRelocating) return; + + setIsRelocating(true); + (Taro as any).showLoading({ title: '定位中...', mask: true }); + + try { + // 获取当前位置 + const location = await getCurrentLocation(); + + if (location && location.latitude && location.longitude) { + // 更新 store 中的位置信息 + updateState?.({ location }); + + // 调用接口把位置传递给后端,传递一个值代表强制更新 + const response = await updateUserLocation(location.latitude, location.longitude, true); + + // 如果接口返回成功,重新调用用户信息接口来更新 USER_SELECTED_CITY + if (response?.code === 0) { + + // 删除 缓存 + (Taro as any).removeStorageSync("USER_SELECTED_CITY"); + + // 延时一下 + await new Promise(resolve => setTimeout(resolve, 600)); + // 先清除缓存和 area,确保使用最新的用户信息 + await updateCache( ["中国", response.data.last_location_province]); + + } + + (Taro as any).showToast({ + title: '定位成功', + icon: 'success', + duration: 1500, + }); + + // 通知父组件位置已更新,可以刷新列表 + if (onRelocate) { + onRelocate(location); + } + } else { + throw new Error('获取位置信息失败'); + } + } catch (error: any) { + console.error('重新定位失败:', error); + (Taro as any).showToast({ + title: error?.message || '定位失败,请检查定位权限', + icon: 'none', + duration: 2000, + }); + } finally { + setIsRelocating(false); + (Taro as any).hideLoading(); + } + }; + // 监听菜单状态变化,通知父组件 useEffect(() => { onMenuVisibleChange?.(isMenuOpen); @@ -103,8 +170,11 @@ const DistanceQuickFilterV2 = (props) => { icon={} >
-

当前位置

-

{currentCity}

+

{currentCity}

+

+ + 重新定位 +

= (props) => { }; const handleMenuItemClick = (type: "individual" | "group" | "ai") => { const [_, address] = area; - if (address !== '上海') { + if (address !== '上海市') { (Taro as any).showModal({ title: '提示', content: '仅上海地区开放,您可加入社群或切换城市', diff --git a/src/components/SearchBar/index.tsx b/src/components/SearchBar/index.tsx index f18e8f7..a77974c 100644 --- a/src/components/SearchBar/index.tsx +++ b/src/components/SearchBar/index.tsx @@ -45,7 +45,7 @@ const SearchBarComponent = (props: IProps) => { } className={styles.searchBar} - placeholder="搜索上海的球局和场地" + placeholder="搜索球局和场地" onChange={handleChange} value={value} onInputClick={onInputClick} diff --git a/src/config/images.js b/src/config/images.js index 57e03c6..62eaddb 100644 --- a/src/config/images.js +++ b/src/config/images.js @@ -70,4 +70,5 @@ export default { ICON_LIST_NTPR: require('@/static/list/ntpr.svg'), ICON_LIST_CHANGDA: require('@/static/list/icon-changda.svg'), ICON_LIST_CHANGDA_QIuju: require('@/static/list/changdaqiuju.png'), + ICON_RELOCATE: require('@/static/list/icon-relocate.svg'), } diff --git a/src/game_pages/search/index.tsx b/src/game_pages/search/index.tsx index 6668a8a..f4a3022 100644 --- a/src/game_pages/search/index.tsx +++ b/src/game_pages/search/index.tsx @@ -131,7 +131,7 @@ const ListSearch = () => { = ({ }); }; + // 处理重新定位 + const handleRelocate = async (location) => { + try { + // 位置已更新到后端,刷新列表数据 + await getMatchesData(); + await fetchGetGamesCount(); + } catch (error) { + console.error("刷新列表失败:", error); + } + }; + const handleSearchClick = () => { navigateTo({ url: "/game_pages/search/index", @@ -508,7 +519,7 @@ const ListPageContent: React.FC = ({ // 判定是否显示"暂无球局"页面 // 条件:省份不是上海 或 (已加载完成且球局数量为0) - const shouldShowNoGames = province !== "上海"; + const shouldShowNoGames = province !== "上海市"; return ( <> @@ -559,6 +570,7 @@ const ListPageContent: React.FC = ({ quickValue={distanceQuickFilter?.order} districtValue={distanceQuickFilter?.district} onMenuVisibleChange={handleDistanceFilterVisibleChange} + onRelocate={handleRelocate} /> diff --git a/src/services/userService.ts b/src/services/userService.ts index 2309e80..e1bc150 100644 --- a/src/services/userService.ts +++ b/src/services/userService.ts @@ -2,7 +2,7 @@ import { UserInfo } from "@/components/UserInfo"; import { API_CONFIG } from "@/config/api"; import httpService, { ApiResponse } from "./httpService"; import uploadFiles from "./uploadFiles"; -import Taro from "@tarojs/taro"; +import * as Taro from "@tarojs/taro"; import getCurrentConfig from "@/config/env"; import { clear_login_state } from "@/services/loginService"; @@ -740,12 +740,14 @@ export const updateUserProfile = async (payload: Partial) => { // 更新用户坐标位置 export const updateUserLocation = async ( latitude: number, - longitude: number + longitude: number, + force: boolean = false ) => { try { const response = await httpService.post("/user/update_location", { latitude, longitude, + force }); return response; } catch (error) { diff --git a/src/static/list/icon-relocate.svg b/src/static/list/icon-relocate.svg new file mode 100644 index 0000000..8100302 --- /dev/null +++ b/src/static/list/icon-relocate.svg @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/src/store/listStore.ts b/src/store/listStore.ts index 128589e..a09c7d5 100644 --- a/src/store/listStore.ts +++ b/src/store/listStore.ts @@ -731,16 +731,16 @@ export const useListStore = create()((set, get) => ({ const state = get(); // 从 area 中获取省份,area 格式: ["中国", 省份, 城市] const country = "中国"; - const province = state.area?.at(1) || "上海"; // area[1] 是省份 - + const cn_city = state.area?.at(1) || "上海市"; // area[1] 是省份 + const res = await getDistricts({ country, - state: province + state: cn_city }); if (res.code === 0 && res.data) { const districts = res.data.map((item) => ({ - label: item.cn_city, + label: item.cn_county, value: item.id.toString(), id: item.id, })); diff --git a/src/store/userStore.ts b/src/store/userStore.ts index 1b35edd..f1d4550 100644 --- a/src/store/userStore.ts +++ b/src/store/userStore.ts @@ -36,6 +36,7 @@ const getTimeNextDate = (time: string) => { // 请求锁,避免重复调用 let isFetchingLastTestResult = false; let isCheckingNicknameStatus = false; +const CITY_CACHE_KEY = "USER_SELECTED_CITY"; export const useUser = create()((set) => ({ user: {}, @@ -44,41 +45,50 @@ export const useUser = create()((set) => ({ const res = await fetchUserProfile(); const userData = res.data; set({ user: userData }); - + // 优先使用缓存中的城市,不使用用户信息中的位置 // 检查是否有缓存的城市 - 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 不存在时才使用用户信息中的位置 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); - } + useUser.getState().updateCache(newArea); } } - + return userData; } catch (error) { console.error("获取用户信息失败:", error); return undefined; } }, + + // 更新缓存 + updateCache: async (newArea: [string, string]) => { + try { + (Taro as any).setStorageSync?.(CITY_CACHE_KEY, newArea); + } catch (error) { + console.error("保存城市缓存失败:", error); + } + }, + updateUserInfo: async (userInfo: Partial) => { try { // 先更新后端 @@ -86,7 +96,7 @@ export const useUser = create()((set) => ({ // 然后立即更新本地状态(乐观更新) set((state) => { const newUser = { ...state.user, ...userInfo }; - + // 当 userLastLocationProvince 更新时,同步更新 area if (userInfo.last_location_province) { const listStore = useListStore.getState(); @@ -97,7 +107,7 @@ export const useUser = create()((set) => ({ listStore.updateArea(newArea); } } - + return { user: newUser }; }); // 不再每次都重新获取完整用户信息,减少请求次数 @@ -195,6 +205,7 @@ export const useNicknameChangeStatus = () => export const useUserActions = () => useUser((state) => ({ fetchUserInfo: state.fetchUserInfo, + updateCache: state.updateCache, updateUserInfo: state.updateUserInfo, checkNicknameChangeStatus: state.checkNicknameChangeStatus, updateNickname: state.updateNickname,