Files
mini-programs/src/main_pages/components/MyselfPageContent.tsx
2026-02-25 16:42:14 +08:00

350 lines
11 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import React, { useState, useEffect, useCallback } from "react";
import { View, Text, Image, ScrollView } from "@tarojs/components";
import Taro from "@tarojs/taro";
import styles from "./MyselfPageContent.module.scss";
import { UserInfoCard } from "@/components/UserInfo/index";
import { UserService } from "@/services/userService";
import ListContainer from "@/container/listContainer";
import { TennisMatch } from "@/../types/list/types";
import { NTRPTestEntryCard } from "@/components";
import { EvaluateScene } from "@/store/evaluateStore";
import { useUserInfo, useUserActions } from "@/store/userStore";
import { usePickerOption } from "@/store/pickerOptionsStore";
import { useGlobalState } from "@/store/global";
import { useListState } from "@/store/listStore";
import { useDictionaryStore } from "@/store/dictionaryStore";
interface MyselfPageContentProps {
isActive?: boolean;
}
const MyselfPageContent: React.FC<MyselfPageContentProps> = ({
isActive = true,
}) => {
const pickerOption = usePickerOption();
const { statusNavbarHeightInfo } = useGlobalState() || {};
const { totalHeight = 98 } = statusNavbarHeightInfo || {};
const { fetchUserInfo } = useUserActions();
const instance = (Taro as any).getCurrentInstance();
const user_id = instance.router?.params?.userid || "";
// const is_current_user = !user_id;
const user_info = useUserInfo();
const [game_records, set_game_records] = useState<TennisMatch[]>([]);
const [ended_game_records, setEndedGameRecords] = useState<TennisMatch[]>([]);
const [loading] = useState(false);
const [is_following, setIsFollowing] = useState(false);
const [active_tab, setActiveTab] = useState<"hosted" | "participated">(
"hosted"
);
const [hasLoaded, setHasLoaded] = useState(false); // 记录是否已经加载过数据
const [collapseProfile, setCollapseProfile] = useState(false);
const [refreshing, setRefreshing] = useState(false);
const { area } = useListState();
const supportedCitiesList =
useDictionaryStore((s) => s.getDictionaryValue("supported_cities")) || [];
useEffect(() => {
pickerOption.getCities();
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;
useDidShow(() => {
// 确保从编辑页面返回时刷新数据
});
// 分类球局数据(使用 useCallback 包装,避免每次渲染都创建新函数)
const classifyGameRecords = useCallback(
(
game_records: TennisMatch[]
): { notEndGames: TennisMatch[]; finishedGames: TennisMatch[] } => {
const now = new Date().getTime();
// 使用for
const notEndGames: TennisMatch[] = [];
const finishedGames: TennisMatch[] = [];
for (const game of game_records) {
const { end_time } = game;
const end_time_str = end_time.replace(/\s/, "T");
new Date(end_time_str).getTime() > now
? notEndGames.push(game)
: finishedGames.unshift(game);
}
console.log("notEndGames", notEndGames);
return { notEndGames, finishedGames };
},
[]
);
// 使用 useCallback 包装 load_game_data避免每次渲染都创建新函数
const load_game_data = useCallback(async () => {
try {
if (!user_info || !("id" in user_info)) {
return;
}
let games_data;
if (active_tab === "hosted") {
games_data = await UserService.get_hosted_games(user_info.id);
} else {
games_data = await UserService.get_participated_games(user_info.id);
}
const sorted_games = games_data.sort((a, b) => {
return (
new Date(a.original_start_time.replace(/\s/, "T")).getTime() -
new Date(b.original_start_time.replace(/\s/, "T")).getTime()
);
});
const { notEndGames, finishedGames } = classifyGameRecords(sorted_games);
console.log("notEndGames", notEndGames);
set_game_records(notEndGames);
setEndedGameRecords(finishedGames);
} catch (error) {
console.warn("加载球局数据失败:", error);
}
}, [active_tab, user_info, classifyGameRecords]);
// 只有当页面激活且未加载过数据时才加载接口
useEffect(() => {
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();
}
}, [active_tab, isActive, hasLoaded, loading, load_game_data, user_info]);
const handle_follow = async () => {
try {
const new_following_state = await UserService.toggle_follow(
user_id,
is_following
);
setIsFollowing(new_following_state);
(Taro as any).showToast({
title: new_following_state ? "关注成功" : "已取消关注",
icon: "success",
duration: 1500,
});
} catch (error) {
console.warn("关注操作失败:", error);
(Taro as any).showToast({
title: "操作失败,请重试",
icon: "error",
duration: 2000,
});
}
};
const goPublish = () => {
const [_, address] = area;
if (!supportedCitiesList.includes(address)) {
(Taro as any).showModal({
title: "提示",
content: "该城市尚未开放,您可加入社群或切换城市",
showCancel: false,
confirmText: "知道了",
});
return;
}
(Taro as any).navigateTo({
url: "/publish_pages/publishBall/index",
});
};
const handle_game_orders = () => {
(Taro as any).navigateTo({
url: "/order_pages/orderList/index",
});
};
const handle_wallet = () => {
(Taro as any).navigateTo({
url: "/user_pages/wallet/index",
// url: "/user_pages/other/index?userid=18",
});
};
const handleOnTab = (tab) => {
setActiveTab(tab);
};
// 下拉刷新:刷新用户信息和球局数据
const handle_refresh = async () => {
setRefreshing(true);
try {
await Promise.all([fetchUserInfo(), load_game_data()]);
} catch (error) {
console.warn("刷新失败:", error);
(Taro as any).showToast({
title: "刷新失败,请重试",
icon: "none",
duration: 2000,
});
} finally {
setRefreshing(false);
}
};
// const handleScroll = (event: any) => {
// const scrollData = event.detail;
// setCollapseProfile(scrollData.scrollTop > 1);
// };
return (
<ScrollView
scrollY
refresherBackground="#FAFAFA"
refresherEnabled
refresherTriggered={refreshing}
onRefresherRefresh={handle_refresh}
className={styles.myselfPage}
>
<View
className={styles.myselfPageContentMain}
style={{ paddingTop: `${totalHeight}px` }}
>
<View className={styles.userInfoSection}>
<UserInfoCard
editable={true}
user_info={user_info}
is_current_user={true}
is_following={is_following}
collapseProfile={collapseProfile}
on_follow={handle_follow}
onTab={handleOnTab}
/>
{!collapseProfile ? (
<View className={styles.quickActionsSection}>
<View className={styles.actionCard}>
<View
className={styles.actionContent}
onClick={handle_game_orders}
>
<Image
className={styles.actionIcon}
src={require("@/static/userInfo/order_btn.svg")}
/>
<Text className={styles.actionText}></Text>
</View>
<View className={styles.actionDivider}></View>
<View className={styles.actionContent} onClick={handle_wallet}>
<Image
className={styles.actionIcon}
src={require("@/static/userInfo/wallet.svg")}
/>
<Text className={styles.actionText}></Text>
</View>
</View>
</View>
) : null}
</View>
{!collapseProfile ? (
<View className={styles.testEntryCardBox}>
<NTRPTestEntryCard type={EvaluateScene.user} />
</View>
) : null}
<View className={styles.gameTabsSection}>
<View className={styles.tabContainer}>
<View
className={`${styles.tabItem} ${
active_tab === "hosted" ? styles.active : ""
}`}
onClick={() => setActiveTab("hosted")}
>
<Text className={styles.tabText}></Text>
</View>
<View
className={`${styles.tabItem} ${
active_tab === "participated" ? styles.active : ""
}`}
onClick={() => setActiveTab("participated")}
>
<Text className={styles.tabText}></Text>
</View>
</View>
</View>
<View className={styles.gameListSection}>
<ScrollView scrollY>
<ListContainer
data={game_records}
recommendList={[]}
loading={loading}
error={null}
errorImg="ICON_LIST_EMPTY_CARD"
emptyText="还没有发布过球局"
btnText="去发布"
btnImg="ICON_ADD"
reload={goPublish}
isShowNoData={game_records.length === 0}
loadMoreMatches={() => {}}
collapse={true}
style={{
paddingBottom: ended_game_records.length ? 0 : "90px",
overflow: "hidden",
}}
listLoadErrorWrapperHeight="fit-content"
listLoadErrorWidth="410px"
listLoadErrorHeight="185px"
defaultShowNum={3}
/>
</ScrollView>
</View>
{ended_game_records.length ? (
<>
<View className={styles.endedGameText}></View>
<View className={styles.gameListSection}>
<ScrollView scrollY>
<ListContainer
data={ended_game_records}
recommendList={[]}
loading={loading}
error={null}
errorImg="ICON_LIST_EMPTY_CARD"
isShowNoData={ended_game_records.length === 0}
loadMoreMatches={() => {}}
collapse={true}
style={{ paddingBottom: "90px", overflow: "hidden" }}
listLoadErrorWrapperHeight="fit-content"
listLoadErrorWidth="410px"
listLoadErrorHeight="185px"
defaultShowNum={3}
/>
</ScrollView>
</View>
</>
) : null}
</View>
</ScrollView>
);
};
export default MyselfPageContent;