Files
mini-programs/src/components/HomeNavbar/index.tsx
2025-11-19 16:53:40 +08:00

266 lines
7.5 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 { useEffect, useState } from "react";
import { View, Text, Image } from "@tarojs/components";
import img from "@/config/images";
import { useGlobalState } from "@/store/global";
import { useUserInfo } from "@/store/userStore";
import { useListState } from "@/store/listStore";
import { Input } from "@nutui/nutui-react-taro";
import Taro from "@tarojs/taro";
import "./index.scss";
import { getCurrentFullPath } from "@/utils";
import { CityPicker as PopupPicker } from "@/components/Picker";
interface IProps {
config?: {
showInput?: boolean;
inputLeftIcon?: string;
iconPath?: string;
leftIconClick?: () => void;
title?: string; // 显示标题(用于"我的"页面等)
showTitle?: boolean; // 是否显示标题模式
};
onCityPickerVisibleChange?: (visible: boolean) => void; // 城市选择器显示/隐藏回调
onScrollToTop?: () => void; // 滚动到顶部回调
}
function CityPicker(props) {
const { visible, setVisible, cities, area, setArea, onCityChange } = props;
console.log(cities, "cities");
const [value, setValue] = useState(area);
function onChange(value: any) {
console.log(value, "value");
setValue(value);
setArea(value);
// 切换城市时触发接口调用
if (onCityChange) {
onCityChange(value);
}
}
return (
visible && (
<PopupPicker
options={cities}
visible={visible}
setvisible={setVisible}
value={value}
onChange={onChange}
style={{ zIndex: 9991 }}
/>
)
);
}
/**
* 首页专用导航栏组件
* 支持三种模式:
* 1. Logo + 城市选择 + 球局数量(默认模式)
* 2. 搜索输入框模式showInput = true
* 3. 标题模式showTitle = true用于"我的"页面等)
*/
const HomeNavbar = (props: IProps) => {
const { config, onCityPickerVisibleChange, onScrollToTop } = props;
const {
showInput = false,
inputLeftIcon,
leftIconClick,
title,
showTitle = false,
} = config || {};
const { getLocationLoading, statusNavbarHeightInfo } = useGlobalState();
const {
gamesNum,
searchValue,
cities,
area,
updateArea,
fetchGetGamesCount,
refreshBothLists,
} = useListState();
const { statusBarHeight = 0, navBarHeight = 44 } =
statusNavbarHeightInfo || {};
const [cityPopupVisible, setCityPopupVisible] = useState(false);
// 监听城市选择器状态变化,通知父组件
useEffect(() => {
onCityPickerVisibleChange?.(cityPopupVisible);
}, [cityPopupVisible]);
const userInfo = useUserInfo();
const province = (userInfo as any)?.province || "";
const city = (userInfo as any)?.city || "";
// const district = (userInfo as any)?.district || "";
useEffect(() => {
updateArea(["中国", province, city]);
}, [province, city]);
// const currentAddress = city + district;
const handleInputClick = () => {
const currentPagePath = getCurrentFullPath();
if (currentPagePath === "/game_pages/searchResult/index") {
(Taro as any).navigateBack();
} else {
(Taro as any).navigateTo({
url: "/game_pages/search/index",
});
}
};
// 点击logo
const handleLogoClick = () => {
// 如果当前在列表页,点击后页面回到顶部
if (getCurrentFullPath() === "/main_pages/index") {
// 使用父组件传递的滚动方法(适配 ScrollView
if (onScrollToTop) {
onScrollToTop();
} else {
// 降级方案:使用页面滚动(兼容旧版本)
(Taro as any).pageScrollTo({
scrollTop: 0,
duration: 300,
});
}
}
(Taro as any).redirectTo({
url: "/main_pages/index", // 列表页
});
};
const handleInputLeftIconClick = () => {
if (leftIconClick) {
leftIconClick();
} else {
handleLogoClick();
}
};
const navbarStyle = {
height: `${navBarHeight}px`,
};
function handleToggleCity() {
setCityPopupVisible(true);
}
const area_city = area.at(-1);
// 处理城市切换
const handleCityChange = async (_newArea: any) => {
// 切换城市后,同时更新两个列表接口获取数据
if (refreshBothLists) {
await refreshBothLists();
}
// 更新球局数量
if (fetchGetGamesCount) {
await fetchGetGamesCount();
}
};
return (
<View
className="homeNavbar"
style={{
position: "fixed",
top: 0,
left: 0,
width: "100%",
height: `${navBarHeight}px`,
paddingTop: `${statusBarHeight}px`,
backgroundColor: "transparent",
zIndex: 99,
}}
>
<View className="listNavWrapper">
{/* 标题模式(用于"我的"页面等) */}
{showTitle && (
<View className="titleNavContainer" style={navbarStyle}>
<View className="titleNavContent">
<Text className="titleNavText">{title || "我的"}</Text>
</View>
</View>
)}
{/* 首页logo 导航*/}
{!showTitle && (
<View
className={`listNavContainer toggleElement firstElement hidden
${!showInput ? "visible" : ""}`}
style={navbarStyle}
>
<View className="listNavContentWrapper">
{/* logo */}
<Image
src={img.ICON_LOGO}
className="listNavLogo"
onClick={handleLogoClick}
/>
<View className="listNavLine" />
<View className="listNavContent">
<View className="listNavCityWrapper" onClick={handleToggleCity}>
{/* 位置 */}
<Text className="listNavCity">{area_city}</Text>
{!getLocationLoading && area_city && (
<Image src={img.ICON_CHANGE} className="listNavChange" />
)}
</View>
<View className="listNavInfoWrapper">
<Text className="listNavInfo">{gamesNum}</Text>
</View>
</View>
</View>
</View>
)}
{/* 搜索导航 */}
{!showTitle && (
<View
className={`inputCustomerNavbarContainer toggleElement secondElement hidden ${
showInput && "visible"
} ${showInput ? "inputCustomerNavbarShowInput" : ""}`}
style={navbarStyle}
>
<View className="navContent">
{/* logo */}
<Image
src={inputLeftIcon || img.ICON_LIST_INPUT_LOGO}
className="logo"
onClick={handleInputLeftIconClick}
/>
{/* 搜索框 */}
<View className="searchContainer">
<Image
className="searchIcon icon16"
src={img.ICON_LIST_SEARCH_SEARCH}
/>
<Input
placeholder="搜索球局和场地"
className="navbarInput"
clearable={false}
disabled
value={searchValue}
onClick={handleInputClick}
/>
</View>
</View>
</View>
)}
</View>
{cityPopupVisible && !showTitle && (
<CityPicker
visible={cityPopupVisible}
setVisible={setCityPopupVisible}
cities={cities}
area={area}
setArea={updateArea}
onCityChange={handleCityChange}
/>
)}
</View>
);
};
export default HomeNavbar;