首页只调用必须的接口
This commit is contained in:
@@ -231,13 +231,13 @@ const HomeNavbar = (props: IProps) => {
|
|||||||
|
|
||||||
// 处理城市切换(仅刷新数据,不保存缓存)
|
// 处理城市切换(仅刷新数据,不保存缓存)
|
||||||
const handleCityChangeWithoutCache = async () => {
|
const handleCityChangeWithoutCache = async () => {
|
||||||
// 切换城市后,同时更新两个列表接口获取数据
|
// 切换城市后,同时更新两个列表接口获取数据,传入当前的 area
|
||||||
if (refreshBothLists) {
|
if (refreshBothLists) {
|
||||||
await refreshBothLists();
|
await refreshBothLists(area);
|
||||||
}
|
}
|
||||||
// 更新球局数量
|
// 更新球局数量,传入当前的 area,确保接口请求的地址与界面显示一致
|
||||||
if (fetchGetGamesCount) {
|
if (fetchGetGamesCount) {
|
||||||
await fetchGetGamesCount();
|
await fetchGetGamesCount(area);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -2,9 +2,9 @@ import React, { useState, useEffect, useCallback, memo } from "react";
|
|||||||
import { View, Image, Text } from "@tarojs/components";
|
import { View, Image, Text } from "@tarojs/components";
|
||||||
import { requireLoginWithPhone } from "@/utils/helper";
|
import { requireLoginWithPhone } from "@/utils/helper";
|
||||||
import Taro from "@tarojs/taro";
|
import Taro from "@tarojs/taro";
|
||||||
import { useUserInfo, useUserActions } from "@/store/userStore";
|
import { useUserInfo, useUserActions, useLastTestResult } from "@/store/userStore";
|
||||||
// import { getCurrentFullPath } from "@/utils";
|
// import { getCurrentFullPath } from "@/utils";
|
||||||
import evaluateService, { StageType } from "@/services/evaluateService";
|
import { StageType } from "@/services/evaluateService";
|
||||||
import { waitForAuthInit } from "@/utils/authInit";
|
import { waitForAuthInit } from "@/utils/authInit";
|
||||||
import DocCopy from "@/static/ntrp/ntrp_doc_copy.svg";
|
import DocCopy from "@/static/ntrp/ntrp_doc_copy.svg";
|
||||||
import ArrowRight from "@/static/ntrp/ntrp_arrow_right_color.svg";
|
import ArrowRight from "@/static/ntrp/ntrp_arrow_right_color.svg";
|
||||||
@@ -19,15 +19,16 @@ function NTRPTestEntryCard(props: {
|
|||||||
type: EvaluateScene;
|
type: EvaluateScene;
|
||||||
evaluateCallback?: EvaluateCallback;
|
evaluateCallback?: EvaluateCallback;
|
||||||
}) {
|
}) {
|
||||||
const [testFlag, setTestFlag] = useState(false);
|
|
||||||
const [hasTestInLastMonth, setHasTestInLastMonth] = useState(false);
|
|
||||||
const { type, evaluateCallback } = props;
|
const { type, evaluateCallback } = props;
|
||||||
const userInfo = useUserInfo();
|
const userInfo = useUserInfo();
|
||||||
const { setCallback } = useEvaluate();
|
const { setCallback } = useEvaluate();
|
||||||
const { fetchUserInfo } = useUserActions();
|
const { fetchUserInfo, fetchLastTestResult } = useUserActions();
|
||||||
|
// 使用全局状态中的测试结果,避免重复调用接口
|
||||||
|
const lastTestResult = useLastTestResult();
|
||||||
|
|
||||||
console.log(userInfo);
|
console.log(userInfo);
|
||||||
|
|
||||||
|
// 从全局状态中获取测试结果,如果不存在则调用接口(使用请求锁避免重复调用)
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const init = async () => {
|
const init = async () => {
|
||||||
// 先等待静默登录完成
|
// 先等待静默登录完成
|
||||||
@@ -36,15 +37,17 @@ function NTRPTestEntryCard(props: {
|
|||||||
if (!userInfo.id) {
|
if (!userInfo.id) {
|
||||||
await fetchUserInfo();
|
await fetchUserInfo();
|
||||||
}
|
}
|
||||||
// 获取测试结果
|
// 如果全局状态中没有测试结果,则调用接口(使用请求锁,多个组件同时调用时只会请求一次)
|
||||||
const res = await evaluateService.getLastResult();
|
if (!lastTestResult) {
|
||||||
if (res.code === 0) {
|
await fetchLastTestResult();
|
||||||
setTestFlag(res.data.has_test_record);
|
|
||||||
setHasTestInLastMonth(res.data.has_test_in_last_month);
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
init();
|
init();
|
||||||
}, [userInfo]);
|
}, [userInfo.id, fetchUserInfo, fetchLastTestResult, lastTestResult]);
|
||||||
|
|
||||||
|
// 从全局状态中计算标志位
|
||||||
|
const testFlag = lastTestResult?.has_test_record || false;
|
||||||
|
const hasTestInLastMonth = lastTestResult?.has_test_in_last_month || false;
|
||||||
|
|
||||||
const handleTest = useCallback(
|
const handleTest = useCallback(
|
||||||
function () {
|
function () {
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ import "./index.scss";
|
|||||||
import { EditModal } from "@/components";
|
import { EditModal } from "@/components";
|
||||||
import { UserService, PickerOption } from "@/services/userService";
|
import { UserService, PickerOption } from "@/services/userService";
|
||||||
import { PopupPicker } from "@/components/Picker/index";
|
import { PopupPicker } from "@/components/Picker/index";
|
||||||
import { useUserActions, useNicknameChangeStatus } from "@/store/userStore";
|
import { useUserActions, useNicknameChangeStatus, useLastTestResult } from "@/store/userStore";
|
||||||
import { UserInfoType } from "@/services/userService";
|
import { UserInfoType } from "@/services/userService";
|
||||||
import {
|
import {
|
||||||
useCities,
|
useCities,
|
||||||
@@ -15,7 +15,6 @@ import {
|
|||||||
} from "@/store/pickerOptionsStore";
|
} from "@/store/pickerOptionsStore";
|
||||||
import { formatNtrpDisplay } from "@/utils/helper";
|
import { formatNtrpDisplay } from "@/utils/helper";
|
||||||
import { useGlobalState } from "@/store/global";
|
import { useGlobalState } from "@/store/global";
|
||||||
import evaluateService from "@/services/evaluateService";
|
|
||||||
|
|
||||||
// 用户信息接口
|
// 用户信息接口
|
||||||
// export interface UserInfo {
|
// export interface UserInfo {
|
||||||
@@ -83,9 +82,10 @@ const UserInfoCardComponent: React.FC<UserInfoCardProps> = ({
|
|||||||
}) => {
|
}) => {
|
||||||
const nickname_change_status = useNicknameChangeStatus();
|
const nickname_change_status = useNicknameChangeStatus();
|
||||||
const { setShowGuideBar } = useGlobalState();
|
const { setShowGuideBar } = useGlobalState();
|
||||||
const { updateUserInfo, updateNickname } = useUserActions();
|
const { updateUserInfo, updateNickname, fetchLastTestResult } = useUserActions();
|
||||||
const ntrpLevels = useNtrpLevels();
|
const ntrpLevels = useNtrpLevels();
|
||||||
const [ntrpTested, setNtrpTested] = useState(false);
|
// 使用全局状态中的测试结果,避免重复调用接口
|
||||||
|
const lastTestResult = useLastTestResult();
|
||||||
|
|
||||||
// 使用 useRef 记录上一次的 user_info,只在真正变化时打印
|
// 使用 useRef 记录上一次的 user_info,只在真正变化时打印
|
||||||
const prevUserInfoRef = useRef<Partial<UserInfoType>>();
|
const prevUserInfoRef = useRef<Partial<UserInfoType>>();
|
||||||
@@ -98,15 +98,14 @@ const UserInfoCardComponent: React.FC<UserInfoCardProps> = ({
|
|||||||
console.log("UserInfoCard 用户信息变化:", user_info);
|
console.log("UserInfoCard 用户信息变化:", user_info);
|
||||||
prevUserInfoRef.current = user_info;
|
prevUserInfoRef.current = user_info;
|
||||||
}
|
}
|
||||||
const getLastResult = async () => {
|
// 如果全局状态中没有测试结果,则调用接口(使用请求锁,多个组件同时调用时只会请求一次)
|
||||||
// 获取测试结果
|
if (!lastTestResult && user_info?.id) {
|
||||||
const res = await evaluateService.getLastResult();
|
fetchLastTestResult();
|
||||||
if (res.code === 0) {
|
}
|
||||||
setNtrpTested(res.data.has_test_in_last_month);
|
}, [user_info?.id, lastTestResult, fetchLastTestResult]);
|
||||||
}
|
|
||||||
};
|
// 从全局状态中获取测试状态
|
||||||
getLastResult();
|
const ntrpTested = lastTestResult?.has_test_in_last_month || false;
|
||||||
}, [user_info]);
|
|
||||||
|
|
||||||
// 编辑个人简介弹窗状态
|
// 编辑个人简介弹窗状态
|
||||||
const [edit_modal_visible, setEditModalVisible] = useState(false);
|
const [edit_modal_visible, setEditModalVisible] = useState(false);
|
||||||
|
|||||||
@@ -3,11 +3,9 @@ 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 { useReachBottom } from "@tarojs/taro";
|
import { useReachBottom } from "@tarojs/taro";
|
||||||
import { useUserInfo, useUserActions } from "@/store/userStore";
|
import { useUserInfo, useUserActions, useLastTestResult } from "@/store/userStore";
|
||||||
import { setStorage, getStorage } from "@/store/storage";
|
|
||||||
import { NTRPTestEntryCard } from "@/components";
|
import { NTRPTestEntryCard } from "@/components";
|
||||||
import { EvaluateScene } from "@/store/evaluateStore";
|
import { EvaluateScene } from "@/store/evaluateStore";
|
||||||
import evaluateService from "@/services/evaluateService";
|
|
||||||
import { waitForAuthInit } from "@/utils/authInit";
|
import { waitForAuthInit } from "@/utils/authInit";
|
||||||
import "./index.scss";
|
import "./index.scss";
|
||||||
import { useRef, useEffect, useState, useMemo } from "react";
|
import { useRef, useEffect, useState, useMemo } from "react";
|
||||||
@@ -40,10 +38,11 @@ const ListContainer = (props) => {
|
|||||||
|
|
||||||
const [showNumber, setShowNumber] = useState(0);
|
const [showNumber, setShowNumber] = useState(0);
|
||||||
const [showSkeleton, setShowSkeleton] = useState(false);
|
const [showSkeleton, setShowSkeleton] = useState(false);
|
||||||
const [hasTestInLastMonth, setHasTestInLastMonth] = useState(false);
|
|
||||||
|
|
||||||
const userInfo = useUserInfo();
|
const userInfo = useUserInfo();
|
||||||
const { fetchUserInfo } = useUserActions();
|
const { fetchUserInfo, fetchLastTestResult } = useUserActions();
|
||||||
|
// 使用全局状态中的测试结果,避免重复调用接口
|
||||||
|
const lastTestResult = useLastTestResult();
|
||||||
|
|
||||||
useReachBottom(() => {
|
useReachBottom(() => {
|
||||||
// 加载更多方法
|
// 加载更多方法
|
||||||
@@ -100,17 +99,21 @@ const ListContainer = (props) => {
|
|||||||
// 先等待静默登录完成
|
// 先等待静默登录完成
|
||||||
await waitForAuthInit();
|
await waitForAuthInit();
|
||||||
// 然后再获取用户信息
|
// 然后再获取用户信息
|
||||||
if (!userInfo.id) {
|
const userInfoId = userInfo && 'id' in userInfo ? userInfo.id : null;
|
||||||
|
if (!userInfoId) {
|
||||||
await fetchUserInfo();
|
await fetchUserInfo();
|
||||||
|
return; // 等待下一次 useEffect 触发(此时 userInfo.id 已有值)
|
||||||
}
|
}
|
||||||
// 获取测试结果
|
// 如果全局状态中没有测试结果,则调用接口(使用请求锁,多个组件同时调用时只会请求一次)
|
||||||
const res = await evaluateService.getLastResult();
|
if (!lastTestResult) {
|
||||||
if (res.code === 0) {
|
await fetchLastTestResult();
|
||||||
setHasTestInLastMonth(res.data.has_test_in_last_month);
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
init();
|
init();
|
||||||
}, [evaluateFlag, userInfo.id]);
|
}, [evaluateFlag, userInfo, lastTestResult, fetchLastTestResult]);
|
||||||
|
|
||||||
|
// 从全局状态中获取测试状态
|
||||||
|
const hasTestInLastMonth = lastTestResult?.has_test_in_last_month || false;
|
||||||
|
|
||||||
if (error) {
|
if (error) {
|
||||||
return <ListLoadError reload={reload} />;
|
return <ListLoadError reload={reload} />;
|
||||||
|
|||||||
@@ -13,6 +13,7 @@ import { useDictionaryStore } from "@/store/dictionaryStore";
|
|||||||
import { saveImage, navigateTo } from "@/utils";
|
import { saveImage, navigateTo } from "@/utils";
|
||||||
|
|
||||||
export interface ListPageContentProps {
|
export interface ListPageContentProps {
|
||||||
|
isActive?: boolean; // 是否处于激活状态(当前显示的页面)
|
||||||
onNavStateChange?: (state: {
|
onNavStateChange?: (state: {
|
||||||
isShowInputCustomerNavBar?: boolean;
|
isShowInputCustomerNavBar?: boolean;
|
||||||
isDistanceFilterVisible?: boolean;
|
isDistanceFilterVisible?: boolean;
|
||||||
@@ -26,6 +27,7 @@ export interface ListPageContentProps {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const ListPageContent: React.FC<ListPageContentProps> = ({
|
const ListPageContent: React.FC<ListPageContentProps> = ({
|
||||||
|
isActive = true,
|
||||||
onNavStateChange,
|
onNavStateChange,
|
||||||
onScrollToTop: _onScrollToTop,
|
onScrollToTop: _onScrollToTop,
|
||||||
scrollToTopTrigger,
|
scrollToTopTrigger,
|
||||||
@@ -53,6 +55,7 @@ const ListPageContent: React.FC<ListPageContentProps> = ({
|
|||||||
initialFilterSearch,
|
initialFilterSearch,
|
||||||
loadMoreMatches,
|
loadMoreMatches,
|
||||||
fetchGetGamesCount,
|
fetchGetGamesCount,
|
||||||
|
refreshBothLists,
|
||||||
updateDistanceQuickFilter,
|
updateDistanceQuickFilter,
|
||||||
getCities,
|
getCities,
|
||||||
getCityQrCode,
|
getCityQrCode,
|
||||||
@@ -86,6 +89,9 @@ const ListPageContent: React.FC<ListPageContentProps> = ({
|
|||||||
const [showSearchBar, setShowSearchBar] = useState(true);
|
const [showSearchBar, setShowSearchBar] = useState(true);
|
||||||
const [scrollTop, setScrollTop] = useState(0);
|
const [scrollTop, setScrollTop] = useState(0);
|
||||||
const [refreshing, setRefreshing] = useState(false);
|
const [refreshing, setRefreshing] = useState(false);
|
||||||
|
// 记录上一次加载数据时的城市,用于检测城市变化
|
||||||
|
const lastLoadedAreaRef = useRef<[string, string] | null>(null);
|
||||||
|
const prevIsActiveRef = useRef(isActive);
|
||||||
|
|
||||||
// 处理距离筛选显示/隐藏
|
// 处理距离筛选显示/隐藏
|
||||||
const handleDistanceFilterVisibleChange = useCallback(
|
const handleDistanceFilterVisibleChange = useCallback(
|
||||||
@@ -200,11 +206,80 @@ const ListPageContent: React.FC<ListPageContentProps> = ({
|
|||||||
getCityQrCode();
|
getCityQrCode();
|
||||||
getDistricts(); // 新增:获取行政区列表
|
getDistricts(); // 新增:获取行政区列表
|
||||||
|
|
||||||
getLocation().catch((error) => {
|
// 只有当页面激活时才加载位置和列表数据
|
||||||
console.error('获取位置信息失败:', error);
|
if (isActive) {
|
||||||
});
|
getLocation().catch((error) => {
|
||||||
|
console.error('获取位置信息失败:', error);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}, [isActive]);
|
||||||
|
|
||||||
}, []);
|
// 当页面从非激活状态切换为激活状态时,检查城市是否变化,如果变化则重新加载数据
|
||||||
|
useEffect(() => {
|
||||||
|
// 如果从非激活状态变为激活状态(切回列表页)
|
||||||
|
if (isActive && !prevIsActiveRef.current) {
|
||||||
|
const currentArea = area;
|
||||||
|
const lastArea = lastLoadedAreaRef.current;
|
||||||
|
|
||||||
|
// 检查城市是否发生变化(比较省份)
|
||||||
|
const currentProvince = currentArea?.[1] || "";
|
||||||
|
const lastProvince = lastArea?.[1] || "";
|
||||||
|
|
||||||
|
// 如果城市发生变化,或者地址存在但不一致,需要重新加载数据
|
||||||
|
// 注意:即使 lastArea 为空,只要 currentArea 存在,也应该加载数据
|
||||||
|
if (currentProvince && (currentProvince !== lastProvince || !lastArea)) {
|
||||||
|
console.log("切回列表页,检测到地址变化或不一致,重新加载数据:", {
|
||||||
|
lastArea,
|
||||||
|
currentArea,
|
||||||
|
lastProvince,
|
||||||
|
currentProvince,
|
||||||
|
});
|
||||||
|
|
||||||
|
// 地址发生变化或不一致,重新加载数据和球局数量
|
||||||
|
const promises: Promise<any>[] = [];
|
||||||
|
if (refreshBothLists) {
|
||||||
|
promises.push(refreshBothLists(currentArea));
|
||||||
|
}
|
||||||
|
if (fetchGetGamesCount) {
|
||||||
|
promises.push(fetchGetGamesCount(currentArea));
|
||||||
|
}
|
||||||
|
Promise.all(promises).then(() => {
|
||||||
|
// 数据加载完成后,更新记录的城市(记录为上一次在列表页加载数据时的城市)
|
||||||
|
if (currentArea) {
|
||||||
|
lastLoadedAreaRef.current = [...currentArea] as [string, string];
|
||||||
|
}
|
||||||
|
}).catch((error) => {
|
||||||
|
console.error("重新加载数据失败:", error);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 如果是首次加载且列表页激活,记录当前城市(用于后续比较)
|
||||||
|
if (isActive && !lastLoadedAreaRef.current && area) {
|
||||||
|
lastLoadedAreaRef.current = [...area] as [string, string];
|
||||||
|
}
|
||||||
|
|
||||||
|
// 更新上一次的激活状态
|
||||||
|
prevIsActiveRef.current = isActive;
|
||||||
|
}, [isActive, area, refreshBothLists, fetchGetGamesCount]);
|
||||||
|
|
||||||
|
// 监听城市变化(在列表页激活状态下),当城市切换后立即更新记录
|
||||||
|
// 注意:这个 useEffect 用于处理在列表页激活状态下切换城市的情况
|
||||||
|
// 当用户在列表页切换城市时,HomeNavbar 的 handleCityChange 已经会调用 refreshBothLists
|
||||||
|
// 这里只需要同步更新 lastLoadedAreaRef,确保后续检测逻辑正确
|
||||||
|
useEffect(() => {
|
||||||
|
// 如果页面激活且城市发生变化(用户在列表页切换了城市)
|
||||||
|
if (isActive && area) {
|
||||||
|
const currentProvince = area[1] || "";
|
||||||
|
const lastProvince = lastLoadedAreaRef.current?.[1] || "";
|
||||||
|
|
||||||
|
// 如果城市发生变化,立即更新记录(因为 refreshBothLists 已经在 HomeNavbar 中调用)
|
||||||
|
if (currentProvince && currentProvince !== lastProvince) {
|
||||||
|
// 立即更新记录,确保地址显示和使用的地址一致
|
||||||
|
lastLoadedAreaRef.current = [...area] as [string, string];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}, [isActive, area]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (pageOption?.page === 1 && matches?.length > 0) {
|
if (pageOption?.page === 1 && matches?.length > 0) {
|
||||||
@@ -237,8 +312,13 @@ const ListPageContent: React.FC<ListPageContentProps> = ({
|
|||||||
console.error("更新用户位置失败:", error);
|
console.error("更新用户位置失败:", error);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
fetchGetGamesCount();
|
// 传入当前的 area,确保接口请求的地址与界面显示一致
|
||||||
getMatchesData();
|
await fetchGetGamesCount(area);
|
||||||
|
await getMatchesData();
|
||||||
|
// 初始数据加载完成后,记录当前城市
|
||||||
|
if (area && isActive) {
|
||||||
|
lastLoadedAreaRef.current = [...area] as [string, string];
|
||||||
|
}
|
||||||
return location;
|
return location;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
import { useState, useEffect } from "react";
|
import { useState, useEffect } from "react";
|
||||||
|
import React from "react";
|
||||||
import { View, Text, Image, ScrollView } from "@tarojs/components";
|
import { View, Text, Image, ScrollView } from "@tarojs/components";
|
||||||
import { EmptyState } from "@/components";
|
import { EmptyState } from "@/components";
|
||||||
import SubscribeNotificationTip from "@/components/SubscribeNotificationTip";
|
import SubscribeNotificationTip from "@/components/SubscribeNotificationTip";
|
||||||
@@ -25,7 +26,11 @@ interface MessageItem {
|
|||||||
|
|
||||||
type MessageCategory = "comment" | "follow";
|
type MessageCategory = "comment" | "follow";
|
||||||
|
|
||||||
const MessagePageContent = () => {
|
interface MessagePageContentProps {
|
||||||
|
isActive?: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
const MessagePageContent: React.FC<MessagePageContentProps> = ({ isActive = true }) => {
|
||||||
const { statusNavbarHeightInfo } = useGlobalState() || {};
|
const { statusNavbarHeightInfo } = useGlobalState() || {};
|
||||||
const { totalHeight = 98 } = statusNavbarHeightInfo || {};
|
const { totalHeight = 98 } = statusNavbarHeightInfo || {};
|
||||||
|
|
||||||
@@ -34,6 +39,7 @@ const MessagePageContent = () => {
|
|||||||
const [loading, setLoading] = useState(false);
|
const [loading, setLoading] = useState(false);
|
||||||
const [reachedBottom, setReachedBottom] = useState(false);
|
const [reachedBottom, setReachedBottom] = useState(false);
|
||||||
const [refreshing, setRefreshing] = useState(false);
|
const [refreshing, setRefreshing] = useState(false);
|
||||||
|
const [hasLoaded, setHasLoaded] = useState(false); // 记录是否已经加载过数据
|
||||||
|
|
||||||
// 从 store 获取红点信息
|
// 从 store 获取红点信息
|
||||||
const reddotInfo = useReddotInfo();
|
const reddotInfo = useReddotInfo();
|
||||||
@@ -58,10 +64,14 @@ const MessagePageContent = () => {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// 只有当页面激活且未加载过数据时才加载接口
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
getNoticeList();
|
if (isActive && !hasLoaded) {
|
||||||
fetchReddotInfo();
|
getNoticeList();
|
||||||
}, []);
|
fetchReddotInfo();
|
||||||
|
setHasLoaded(true);
|
||||||
|
}
|
||||||
|
}, [isActive, hasLoaded]);
|
||||||
|
|
||||||
const filteredMessages = messageList;
|
const filteredMessages = messageList;
|
||||||
|
|
||||||
|
|||||||
@@ -8,14 +8,19 @@ import ListContainer from "@/container/listContainer";
|
|||||||
import { TennisMatch } from "@/../types/list/types";
|
import { TennisMatch } from "@/../types/list/types";
|
||||||
import { NTRPTestEntryCard } from "@/components";
|
import { NTRPTestEntryCard } from "@/components";
|
||||||
import { EvaluateScene } from "@/store/evaluateStore";
|
import { EvaluateScene } from "@/store/evaluateStore";
|
||||||
import { useUserInfo } from "@/store/userStore";
|
import { useUserInfo, useUserActions } from "@/store/userStore";
|
||||||
import { usePickerOption } from "@/store/pickerOptionsStore";
|
import { usePickerOption } from "@/store/pickerOptionsStore";
|
||||||
import { useGlobalState } from "@/store/global";
|
import { useGlobalState } from "@/store/global";
|
||||||
|
|
||||||
const MyselfPageContent: React.FC = () => {
|
interface MyselfPageContentProps {
|
||||||
|
isActive?: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
const MyselfPageContent: React.FC<MyselfPageContentProps> = ({ isActive = true }) => {
|
||||||
const pickerOption = usePickerOption();
|
const pickerOption = usePickerOption();
|
||||||
const { statusNavbarHeightInfo } = useGlobalState() || {};
|
const { statusNavbarHeightInfo } = useGlobalState() || {};
|
||||||
const { totalHeight = 98 } = statusNavbarHeightInfo || {};
|
const { totalHeight = 98 } = statusNavbarHeightInfo || {};
|
||||||
|
const { fetchUserInfo } = useUserActions();
|
||||||
|
|
||||||
const instance = (Taro as any).getCurrentInstance();
|
const instance = (Taro as any).getCurrentInstance();
|
||||||
const user_id = instance.router?.params?.userid || "";
|
const user_id = instance.router?.params?.userid || "";
|
||||||
@@ -29,6 +34,7 @@ const MyselfPageContent: React.FC = () => {
|
|||||||
const [active_tab, setActiveTab] = useState<"hosted" | "participated">(
|
const [active_tab, setActiveTab] = useState<"hosted" | "participated">(
|
||||||
"hosted"
|
"hosted"
|
||||||
);
|
);
|
||||||
|
const [hasLoaded, setHasLoaded] = useState(false); // 记录是否已经加载过数据
|
||||||
|
|
||||||
const [collapseProfile, setCollapseProfile] = useState(false);
|
const [collapseProfile, setCollapseProfile] = useState(false);
|
||||||
|
|
||||||
@@ -37,6 +43,16 @@ const MyselfPageContent: React.FC = () => {
|
|||||||
pickerOption.getProfessions();
|
pickerOption.getProfessions();
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
|
// 当页面激活时,确保用户信息已加载
|
||||||
|
useEffect(() => {
|
||||||
|
if (isActive) {
|
||||||
|
// 如果用户信息不存在或没有 id,则加载用户信息
|
||||||
|
if (!user_info || !("id" in user_info) || !user_info.id) {
|
||||||
|
fetchUserInfo();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}, [isActive, user_info, fetchUserInfo]);
|
||||||
|
|
||||||
const { useDidShow } = Taro as any;
|
const { useDidShow } = Taro as any;
|
||||||
useDidShow(() => {
|
useDidShow(() => {
|
||||||
// 确保从编辑页面返回时刷新数据
|
// 确保从编辑页面返回时刷新数据
|
||||||
@@ -92,11 +108,20 @@ const MyselfPageContent: React.FC = () => {
|
|||||||
}
|
}
|
||||||
}, [active_tab, user_info, classifyGameRecords]);
|
}, [active_tab, user_info, classifyGameRecords]);
|
||||||
|
|
||||||
|
// 只有当页面激活且未加载过数据时才加载接口
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (!loading) {
|
if (isActive && !hasLoaded && !loading && user_info && "id" in user_info) {
|
||||||
|
load_game_data();
|
||||||
|
setHasLoaded(true);
|
||||||
|
}
|
||||||
|
}, [isActive, hasLoaded, loading, load_game_data, user_info]);
|
||||||
|
|
||||||
|
// 当 active_tab 切换时,如果页面已激活,重新加载数据
|
||||||
|
useEffect(() => {
|
||||||
|
if (isActive && hasLoaded && !loading && user_info && "id" in user_info) {
|
||||||
load_game_data();
|
load_game_data();
|
||||||
}
|
}
|
||||||
}, [loading, load_game_data]);
|
}, [active_tab, isActive, hasLoaded, loading, load_game_data, user_info]);
|
||||||
|
|
||||||
const handle_follow = async () => {
|
const handle_follow = async () => {
|
||||||
try {
|
try {
|
||||||
|
|||||||
@@ -230,6 +230,7 @@ const MainPage: React.FC = () => {
|
|||||||
className={`tab-content ${currentTab === "list" ? "active" : ""}`}
|
className={`tab-content ${currentTab === "list" ? "active" : ""}`}
|
||||||
>
|
>
|
||||||
<ListPageContent
|
<ListPageContent
|
||||||
|
isActive={currentTab === "list"}
|
||||||
onNavStateChange={handleListNavStateChange}
|
onNavStateChange={handleListNavStateChange}
|
||||||
onScrollToTop={scrollToTop}
|
onScrollToTop={scrollToTop}
|
||||||
scrollToTopTrigger={listPageScrollToTopTrigger}
|
scrollToTopTrigger={listPageScrollToTopTrigger}
|
||||||
@@ -243,14 +244,14 @@ const MainPage: React.FC = () => {
|
|||||||
<View
|
<View
|
||||||
className={`tab-content ${currentTab === "message" ? "active" : ""}`}
|
className={`tab-content ${currentTab === "message" ? "active" : ""}`}
|
||||||
>
|
>
|
||||||
<MessagePageContent />
|
<MessagePageContent isActive={currentTab === "message"} />
|
||||||
</View>
|
</View>
|
||||||
|
|
||||||
{/* 我的页内容 */}
|
{/* 我的页内容 */}
|
||||||
<View
|
<View
|
||||||
className={`tab-content ${currentTab === "personal" ? "active" : ""}`}
|
className={`tab-content ${currentTab === "personal" ? "active" : ""}`}
|
||||||
>
|
>
|
||||||
<MyselfPageContent />
|
<MyselfPageContent isActive={currentTab === "personal"} />
|
||||||
</View>
|
</View>
|
||||||
|
|
||||||
{/* 底部导航栏 */}
|
{/* 底部导航栏 */}
|
||||||
|
|||||||
@@ -193,12 +193,11 @@ export const useListStore = create<TennisStore>()((set, get) => ({
|
|||||||
const distanceQuickFilter = currentPageState?.distanceQuickFilter || {};
|
const distanceQuickFilter = currentPageState?.distanceQuickFilter || {};
|
||||||
const { distanceFilter, order, district } = distanceQuickFilter || {};
|
const { distanceFilter, order, district } = distanceQuickFilter || {};
|
||||||
|
|
||||||
// 优先使用 overrideArea(切换城市时传入),其次使用 area 状态中的省份,最后使用用户信息中的
|
// 优先使用 overrideArea(切换城市时传入),其次使用 area 状态
|
||||||
|
// area 会在 userLastLocationProvince 更新时自动同步,所以这里直接使用 area 即可
|
||||||
const areaProvince = overrideArea?.at(1) || state.area?.at(1) || "";
|
const areaProvince = overrideArea?.at(1) || state.area?.at(1) || "";
|
||||||
const userInfo = useUser.getState().user as any;
|
const userInfo = useUser.getState().user as any;
|
||||||
const userLastLocationProvince = userInfo?.last_location_province || "";
|
const last_location_province = areaProvince;
|
||||||
// 优先使用切换后的城市,如果没有切换过则使用用户信息中的
|
|
||||||
const last_location_province = areaProvince || userLastLocationProvince;
|
|
||||||
const last_location_city = userInfo?.last_location_city || "";
|
const last_location_city = userInfo?.last_location_city || "";
|
||||||
|
|
||||||
// city 参数逻辑:
|
// city 参数逻辑:
|
||||||
@@ -530,7 +529,8 @@ export const useListStore = create<TennisStore>()((set, get) => ({
|
|||||||
// 使用 Promise.resolve 确保状态更新后再调用接口
|
// 使用 Promise.resolve 确保状态更新后再调用接口
|
||||||
Promise.resolve().then(() => {
|
Promise.resolve().then(() => {
|
||||||
const freshState = get(); // 重新获取最新状态
|
const freshState = get(); // 重新获取最新状态
|
||||||
freshState.fetchGetGamesCount();
|
// 传入当前的 area,确保接口请求的地址与界面显示一致
|
||||||
|
freshState.fetchGetGamesCount(freshState.area);
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
@@ -551,7 +551,8 @@ export const useListStore = create<TennisStore>()((set, get) => ({
|
|||||||
Promise.resolve().then(() => {
|
Promise.resolve().then(() => {
|
||||||
const freshState = get(); // 重新获取最新状态
|
const freshState = get(); // 重新获取最新状态
|
||||||
freshState.getMatchesData();
|
freshState.getMatchesData();
|
||||||
freshState.fetchGetGamesCount();
|
// 传入当前的 area,确保接口请求的地址与界面显示一致
|
||||||
|
freshState.fetchGetGamesCount(freshState.area);
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|||||||
@@ -7,6 +7,8 @@ import {
|
|||||||
NicknameChangeStatus,
|
NicknameChangeStatus,
|
||||||
updateNickname as updateNicknameApi,
|
updateNickname as updateNicknameApi,
|
||||||
} from "@/services/userService";
|
} from "@/services/userService";
|
||||||
|
import evaluateService, { LastTimeTestResult } from "@/services/evaluateService";
|
||||||
|
import { useListStore } from "./listStore";
|
||||||
|
|
||||||
export interface UserState {
|
export interface UserState {
|
||||||
user: UserInfoType | {};
|
user: UserInfoType | {};
|
||||||
@@ -15,35 +17,11 @@ export interface UserState {
|
|||||||
nicknameChangeStatus: Partial<NicknameChangeStatus>;
|
nicknameChangeStatus: Partial<NicknameChangeStatus>;
|
||||||
checkNicknameChangeStatus: () => void;
|
checkNicknameChangeStatus: () => void;
|
||||||
updateNickname: (nickname: string) => void;
|
updateNickname: (nickname: string) => void;
|
||||||
|
// NTRP 测试结果缓存
|
||||||
|
lastTestResult: LastTimeTestResult | null;
|
||||||
|
fetchLastTestResult: () => Promise<LastTimeTestResult | null>;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 请求锁,防止重复请求
|
|
||||||
let fetchingUserInfo = false;
|
|
||||||
let fetchUserInfoPromise: Promise<UserInfoType | undefined> | null = null;
|
|
||||||
|
|
||||||
const fetchUserInfoWithLock = async (set) => {
|
|
||||||
// 如果正在请求,直接返回现有的 Promise
|
|
||||||
if (fetchingUserInfo && fetchUserInfoPromise) {
|
|
||||||
return fetchUserInfoPromise;
|
|
||||||
}
|
|
||||||
|
|
||||||
fetchingUserInfo = true;
|
|
||||||
fetchUserInfoPromise = (async () => {
|
|
||||||
try {
|
|
||||||
const res = await fetchUserProfile();
|
|
||||||
set({ user: res.data });
|
|
||||||
return res.data;
|
|
||||||
} catch (error) {
|
|
||||||
console.error("获取用户信息失败:", error);
|
|
||||||
return undefined;
|
|
||||||
} finally {
|
|
||||||
fetchingUserInfo = false;
|
|
||||||
fetchUserInfoPromise = null;
|
|
||||||
}
|
|
||||||
})();
|
|
||||||
|
|
||||||
return fetchUserInfoPromise;
|
|
||||||
};
|
|
||||||
|
|
||||||
const getTimeNextDate = (time: string) => {
|
const getTimeNextDate = (time: string) => {
|
||||||
const date = new Date(time);
|
const date = new Date(time);
|
||||||
@@ -56,15 +34,50 @@ const getTimeNextDate = (time: string) => {
|
|||||||
|
|
||||||
export const useUser = create<UserState>()((set) => ({
|
export const useUser = create<UserState>()((set) => ({
|
||||||
user: {},
|
user: {},
|
||||||
fetchUserInfo: () => fetchUserInfoWithLock(set),
|
fetchUserInfo: async () => {
|
||||||
|
try {
|
||||||
|
const res = await fetchUserProfile();
|
||||||
|
const userData = res.data;
|
||||||
|
set({ user: userData });
|
||||||
|
|
||||||
|
// 当 userLastLocationProvince 更新时,同步更新 area
|
||||||
|
if (userData?.last_location_province) {
|
||||||
|
const listStore = useListStore.getState();
|
||||||
|
const currentArea = listStore.area;
|
||||||
|
// 只有当 area 不存在或与 userLastLocationProvince 不一致时才更新
|
||||||
|
if (!currentArea || currentArea[1] !== userData.last_location_province) {
|
||||||
|
const newArea: [string, string] = ["中国", userData.last_location_province];
|
||||||
|
listStore.updateArea(newArea);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return userData;
|
||||||
|
} catch (error) {
|
||||||
|
console.error("获取用户信息失败:", error);
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
},
|
||||||
updateUserInfo: async (userInfo: Partial<UserInfoType>) => {
|
updateUserInfo: async (userInfo: Partial<UserInfoType>) => {
|
||||||
try {
|
try {
|
||||||
// 先更新后端
|
// 先更新后端
|
||||||
await updateUserProfile(userInfo);
|
await updateUserProfile(userInfo);
|
||||||
// 然后立即更新本地状态(乐观更新)
|
// 然后立即更新本地状态(乐观更新)
|
||||||
set((state) => ({
|
set((state) => {
|
||||||
user: { ...state.user, ...userInfo },
|
const newUser = { ...state.user, ...userInfo };
|
||||||
}));
|
|
||||||
|
// 当 userLastLocationProvince 更新时,同步更新 area
|
||||||
|
if (userInfo.last_location_province) {
|
||||||
|
const listStore = useListStore.getState();
|
||||||
|
const currentArea = listStore.area;
|
||||||
|
// 只有当 area 不存在或与 userLastLocationProvince 不一致时才更新
|
||||||
|
if (!currentArea || currentArea[1] !== userInfo.last_location_province) {
|
||||||
|
const newArea: [string, string] = ["中国", userInfo.last_location_province];
|
||||||
|
listStore.updateArea(newArea);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return { user: newUser };
|
||||||
|
});
|
||||||
// 不再每次都重新获取完整用户信息,减少请求次数
|
// 不再每次都重新获取完整用户信息,减少请求次数
|
||||||
// 只有在更新头像等需要服务器返回新URL的字段时才需要重新获取
|
// 只有在更新头像等需要服务器返回新URL的字段时才需要重新获取
|
||||||
// 如果需要确保数据一致性,可以在特定场景下手动调用 fetchUserInfo
|
// 如果需要确保数据一致性,可以在特定场景下手动调用 fetchUserInfo
|
||||||
@@ -99,6 +112,21 @@ export const useUser = create<UserState>()((set) => ({
|
|||||||
console.error("更新用户昵称失败:", error);
|
console.error("更新用户昵称失败:", error);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
// NTRP 测试结果缓存
|
||||||
|
lastTestResult: null,
|
||||||
|
fetchLastTestResult: async () => {
|
||||||
|
try {
|
||||||
|
const res = await evaluateService.getLastResult();
|
||||||
|
if (res.code === 0) {
|
||||||
|
set({ lastTestResult: res.data });
|
||||||
|
return res.data;
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
} catch (error) {
|
||||||
|
console.error("获取NTRP测试结果失败:", error);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
},
|
||||||
}));
|
}));
|
||||||
|
|
||||||
export const useUserInfo = () => useUser((state) => state.user);
|
export const useUserInfo = () => useUser((state) => state.user);
|
||||||
@@ -111,4 +139,7 @@ export const useUserActions = () =>
|
|||||||
updateUserInfo: state.updateUserInfo,
|
updateUserInfo: state.updateUserInfo,
|
||||||
checkNicknameChangeStatus: state.checkNicknameChangeStatus,
|
checkNicknameChangeStatus: state.checkNicknameChangeStatus,
|
||||||
updateNickname: state.updateNickname,
|
updateNickname: state.updateNickname,
|
||||||
|
fetchLastTestResult: state.fetchLastTestResult,
|
||||||
}));
|
}));
|
||||||
|
|
||||||
|
export const useLastTestResult = () => useUser((state) => state.lastTestResult);
|
||||||
|
|||||||
Reference in New Issue
Block a user