Files
mini-programs/src/main_pages/index.tsx
2025-12-08 13:32:12 +08:00

276 lines
8.8 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 } from "@tarojs/components";
import Taro from "@tarojs/taro";
import { wechat_auth_login, save_login_state } from "@/services/loginService";
import { useUserActions } from "@/store/userStore";
import { useGlobalState } from "@/store/global";
import tokenManager from "@/utils/tokenManager";
import GuideBar from "@/components/GuideBar";
import { GeneralNavbar } from "@/components";
import HomeNavbar from "@/components/HomeNavbar";
import ListPageContent from "./components/ListPageContent";
import MessagePageContent from "./components/MessagePageContent";
import MyselfPageContent from "./components/MyselfPageContent";
import "./index.scss";
import FamilyContext from "@/context";
type TabType = "list" | "message" | "personal";
const MainPage: React.FC = () => {
const [currentTab, setCurrentTab] = useState<TabType>("list");
const [isPublishMenuVisible, setIsPublishMenuVisible] = useState(false);
const [isDistanceFilterVisible, setIsDistanceFilterVisible] = useState(false);
const [isCityPickerVisible, setIsCityPickerVisible] = useState(false);
const [isFilterPopupVisible, setIsFilterPopupVisible] = useState(false);
const [isShowInputCustomerNavBar, setIsShowInputCustomerNavBar] =
useState(false);
const [listPageScrollToTopTrigger, setListPageScrollToTopTrigger] =
useState(0);
const [showAuthError, setShowAuthError] = useState(false);
const [authErrorMessage, setAuthErrorMessage] = useState("");
const { fetchUserInfo, checkNicknameChangeStatus } = useUserActions();
// 从 store 获取 GuideBar 相关状态和方法
const { showGuideBar, guideBarZIndex, setShowGuideBar, setGuideBarZIndex } =
useGlobalState();
// 初始化:自动微信授权并获取用户信息
useEffect(() => {
const init = async () => {
const hasValidToken = tokenManager.hasValidToken();
if (!hasValidToken) {
try {
console.log("开始微信授权...");
const loginRes = await wechat_auth_login();
if (loginRes.success && loginRes.token) {
save_login_state(loginRes.token, loginRes.user_info);
console.log("微信授权成功");
} else {
// 显示错误提示
setAuthErrorMessage(loginRes.message || "微信授权失败");
setShowAuthError(true);
return;
}
} catch (error) {
console.error("微信授权异常:", error);
setAuthErrorMessage("微信授权失败,请重试");
setShowAuthError(true);
return;
}
}
// 如果有有效token获取用户详细信息
if (tokenManager.hasValidToken()) {
try {
await fetchUserInfo();
await checkNicknameChangeStatus();
} catch (error) {
console.error("获取用户信息失败:", error);
}
}
};
init();
// eslint-disable-next-line react-hooks/exhaustive-deps
}, []); // fetchUserInfo 是稳定的函数引用,不需要加入依赖项
// 显示授权错误提示
useEffect(() => {
if (showAuthError) {
Taro.showModal({
title: "授权失败",
content: `${authErrorMessage}\n\n请重启小程序后重试`,
showCancel: false,
confirmText: "我知道了",
success: () => {
setShowAuthError(false);
},
});
}
}, [showAuthError, authErrorMessage]);
// 处理标签切换
const handleTabChange = useCallback(
(code: string) => {
if (code === currentTab) {
return;
}
setCurrentTab(code as TabType);
// 切换标签时滚动到顶部
(Taro as any).pageScrollTo({
scrollTop: 0,
duration: 300,
});
},
[currentTab]
);
// 处理发布菜单显示/隐藏
const handlePublishMenuVisibleChange = useCallback((visible: boolean) => {
setIsPublishMenuVisible(visible);
}, []);
// 处理距离筛选显示/隐藏
const handleDistanceFilterVisibleChange = useCallback((visible: boolean) => {
setIsDistanceFilterVisible(visible);
}, []);
// 处理城市选择器显示/隐藏
const handleCityPickerVisibleChange = useCallback((visible: boolean) => {
setIsCityPickerVisible(visible);
}, []);
// 处理筛选弹窗显示/隐藏
const handleFilterPopupVisibleChange = useCallback((visible: boolean) => {
setIsFilterPopupVisible(visible);
}, []);
// 处理列表页导航状态变化
const handleListNavStateChange = useCallback(
(state: {
isShowInputCustomerNavBar?: boolean;
isDistanceFilterVisible?: boolean;
isCityPickerVisible?: boolean;
}) => {
if (state.isShowInputCustomerNavBar !== undefined) {
setIsShowInputCustomerNavBar(state.isShowInputCustomerNavBar);
}
if (state.isDistanceFilterVisible !== undefined) {
setIsDistanceFilterVisible(state.isDistanceFilterVisible);
}
if (state.isCityPickerVisible !== undefined) {
setIsCityPickerVisible(state.isCityPickerVisible);
}
},
[]
);
// 滚动到顶部
const scrollToTop = useCallback(() => {
// 如果当前是列表页,触发列表页内部滚动
if (currentTab === "list") {
// 通过状态变化触发 ListPageContent 内部滚动
setListPageScrollToTopTrigger((prev) => prev + 1);
} else {
// 其他页面使用 pageScrollTo
(Taro as any).pageScrollTo({
scrollTop: 0,
duration: 300,
});
}
}, [currentTab]);
// 动态控制 GuideBar 的 z-index
useEffect(() => {
if (isPublishMenuVisible) {
setGuideBarZIndex("high");
} else if (
isDistanceFilterVisible ||
isCityPickerVisible ||
isFilterPopupVisible
) {
setGuideBarZIndex("low");
} else {
setGuideBarZIndex("high");
}
}, [
isPublishMenuVisible,
isDistanceFilterVisible,
isCityPickerVisible,
isFilterPopupVisible,
]);
// 渲染自定义导航栏(参考原始页面的实现)
const renderCustomNavbar = () => {
if (currentTab === "list") {
// 列表页:使用 HomeNavbar与原始列表页一致
return (
<HomeNavbar
config={{
showInput: isShowInputCustomerNavBar,
}}
onCityPickerVisibleChange={(visible) => {
setIsCityPickerVisible(visible);
handleListNavStateChange({ isCityPickerVisible: visible });
}}
onScrollToTop={scrollToTop}
/>
);
} else if (currentTab === "message") {
// 消息页:使用 GeneralNavbar与原始消息页一致显示用户头像和标题
return (
<GeneralNavbar
title="消息"
titlePosition="left"
showBack={false}
showAvatar={true}
/>
);
} else if (currentTab === "personal") {
// 我的页:使用 GeneralNavbar 显示标题
return <GeneralNavbar title="" titlePosition="left" showBack={false} />;
}
return null;
};
const handleGrandchildTrigger = (value) => {
console.log("[MainPage] handleGrandchildTrigger called with:", value);
setShowGuideBar(!value);
};
return (
<FamilyContext.Provider value={{ handleGrandchildTrigger }}>
<View className="main-page">
{/* 自定义导航栏 */}
{renderCustomNavbar()}
{/* 列表页内容 */}
<View
className={`tab-content ${currentTab === "list" ? "active" : ""}`}
>
<ListPageContent
isActive={currentTab === "list"}
onNavStateChange={handleListNavStateChange}
onScrollToTop={scrollToTop}
scrollToTopTrigger={listPageScrollToTopTrigger}
onDistanceFilterVisibleChange={handleDistanceFilterVisibleChange}
onCityPickerVisibleChange={handleCityPickerVisibleChange}
onFilterPopupVisibleChange={handleFilterPopupVisibleChange}
/>
</View>
{/* 消息页内容 */}
<View
className={`tab-content ${currentTab === "message" ? "active" : ""}`}
>
<MessagePageContent isActive={currentTab === "message"} />
</View>
{/* 我的页内容 */}
<View
className={`tab-content ${currentTab === "personal" ? "active" : ""}`}
>
<MyselfPageContent isActive={currentTab === "personal"} />
</View>
{/* 底部导航栏 */}
{showGuideBar ? (
<GuideBar
currentPage={currentTab}
guideBarClassName={
guideBarZIndex === "low"
? "guide-bar-low-z-index"
: "guide-bar-high-z-index"
}
onTabChange={handleTabChange}
onPublishMenuVisibleChange={handlePublishMenuVisibleChange}
/>
) : null}
</View>
</FamilyContext.Provider>
);
};
export default MainPage;