293 lines
8.6 KiB
TypeScript
293 lines
8.6 KiB
TypeScript
import { useState, useEffect, useRef } from "react";
|
|
import { View, Text, Image, ScrollView } from "@tarojs/components";
|
|
import Taro, { useRouter, useDidShow } from "@tarojs/taro";
|
|
import classnames from "classnames";
|
|
import { throttle } from "@tarojs/runtime";
|
|
// 导入API服务
|
|
import { withAuth, Comments } from "@/components";
|
|
import DetailService from "@/services/detailService";
|
|
import * as LoginService from "@/services/loginService";
|
|
import { getCurrentLocation } from "@/utils/locationUtils";
|
|
import { useUserInfo, useUserActions } from "@/store/userStore";
|
|
import { useGlobalState } from "@/store/global";
|
|
import { waitForAuthInit } from "@/utils/authInit";
|
|
import { requireLoginWithPhone } from "@/utils/helper";
|
|
import GameTags from "./components/GameTags";
|
|
import Carousel from "./components/Carousel";
|
|
import StickyBottom from "./components/StickyBottom";
|
|
import GameInfo from "./components/GameInfo";
|
|
import VenueInfo from "./components/VenueInfo";
|
|
import GamePlayAndRequirement from "./components/GamePlayAndReq";
|
|
import Participants from "./components/Participants";
|
|
import SupplementalNotes from "./components/SupplementalNotes";
|
|
import OrganizerInfo from "./components/OrganizerInfo";
|
|
import SharePopup from "./components/SharePopup";
|
|
import { navto, toast } from "@/utils/helper";
|
|
import ArrowLeft from "@/static/detail/icon-arrow-left.svg";
|
|
// import Logo from "@/static/detail/icon-logo-go.svg";
|
|
import styles from "./index.module.scss";
|
|
|
|
function Index() {
|
|
const [detail, setDetail] = useState<any>({});
|
|
const { params } = useRouter();
|
|
const [currentLocation, setCurrentLocation] = useState<[number, number]>([
|
|
0, 0,
|
|
]);
|
|
const { id, from, message_id } = params;
|
|
const [userInfo, setUserInfo] = useState({}); // 组织者的userInfo
|
|
const { fetchUserInfo } = useUserActions(); // 获取登录用户的userInfo
|
|
const myInfo = useUserInfo();
|
|
|
|
const { statusNavbarHeightInfo } = useGlobalState();
|
|
const { statusBarHeight, navBarHeight, totalHeight } = statusNavbarHeightInfo;
|
|
|
|
const isMyOwn = userInfo.id === myInfo.id;
|
|
|
|
const sharePopupRef = useRef<any>(null);
|
|
const commentRef = useRef();
|
|
|
|
useEffect(() => {
|
|
const init = async () => {
|
|
updateLocation();
|
|
// 先等待静默登录完成
|
|
await waitForAuthInit();
|
|
// 然后再获取用户信息
|
|
await fetchUserInfo();
|
|
};
|
|
init();
|
|
}, []);
|
|
|
|
useDidShow(() => {
|
|
// await updateLocation();
|
|
// await fetchUserInfo();
|
|
if (id) {
|
|
Taro.showLoading();
|
|
fetchDetail();
|
|
}
|
|
});
|
|
|
|
const updateLocation = async () => {
|
|
try {
|
|
const { address, ...location } = await getCurrentLocation();
|
|
setCurrentLocation([location.latitude, location.longitude]);
|
|
|
|
// 使用 userStore 中的统一位置更新方法
|
|
// await updateUserInfo({ latitude: location.latitude, longitude: location.longitude })
|
|
await DetailService.updateLocation({
|
|
latitude: Number(location.latitude),
|
|
longitude: Number(location.longitude),
|
|
});
|
|
|
|
// 位置更新后,重新获取详情页数据(因为距离等信息可能发生变化)
|
|
await fetchDetail();
|
|
if (from === "publish") {
|
|
handleShare(true);
|
|
}
|
|
} catch (error) {
|
|
console.error("用户位置更新失败", error);
|
|
}
|
|
};
|
|
|
|
const fetchDetail = async () => {
|
|
if (!id) return;
|
|
try {
|
|
const res = await DetailService.getDetail(Number(id));
|
|
if (res.code === 0) {
|
|
setDetail(res.data);
|
|
fetchUserInfoById(res.data.publisher_id);
|
|
}
|
|
} catch (e) {
|
|
if (e.message === "球局不存在") {
|
|
handleBack();
|
|
}
|
|
}
|
|
Taro.hideLoading();
|
|
};
|
|
|
|
const onUpdateUserInfo = () => {
|
|
fetchUserInfoById(detail.publisher_id);
|
|
};
|
|
|
|
async function fetchUserInfoById(user_id) {
|
|
const userDetailInfo = await LoginService.getUserInfoById(user_id);
|
|
if (userDetailInfo.code === 0) {
|
|
setUserInfo(userDetailInfo.data);
|
|
}
|
|
}
|
|
|
|
function handleShare(flag = false) {
|
|
sharePopupRef.current.show(flag);
|
|
}
|
|
|
|
const handleJoinGame = async () => {
|
|
// 检查登录状态和手机号
|
|
if (!requireLoginWithPhone()) {
|
|
return; // 未登录或未绑定手机号,已跳转到登录页
|
|
}
|
|
|
|
if (isMyOwn) {
|
|
const res = await DetailService.organizerJoin(Number(id));
|
|
if (res.code === 0) {
|
|
toast("加入成功");
|
|
fetchDetail();
|
|
}
|
|
return;
|
|
}
|
|
navto(`/order_pages/orderDetail/index?gameId=${id}`);
|
|
};
|
|
|
|
function onStatusChange(result) {
|
|
if (result) {
|
|
fetchDetail();
|
|
}
|
|
}
|
|
|
|
function handleBack() {
|
|
const pages = Taro.getCurrentPages();
|
|
if (pages.length <= 1) {
|
|
Taro.redirectTo({
|
|
url: "/main_pages/index",
|
|
});
|
|
} else {
|
|
Taro.navigateBack();
|
|
}
|
|
}
|
|
|
|
function handleViewUserInfo(userId) {
|
|
navto(
|
|
isMyOwn
|
|
? "/user_pages/myself/index"
|
|
: `/user_pages/other/index?userid=${userId}`
|
|
);
|
|
}
|
|
|
|
const backgroundImage = detail?.image_list?.[0]
|
|
? { backgroundImage: `url(${detail?.image_list?.[0]})` }
|
|
: {};
|
|
|
|
const [glass, setGlass] = useState(false);
|
|
|
|
const onScroll = throttle((e) => {
|
|
const top = e.detail.scrollTop;
|
|
setGlass(top > 20);
|
|
}, 16);
|
|
|
|
return (
|
|
<ScrollView
|
|
className={styles["detail-page"]}
|
|
scrollY
|
|
onScroll={onScroll}
|
|
onScrollToUpper={() => {
|
|
setGlass(false);
|
|
}}
|
|
enhanced
|
|
showScrollbar={false}
|
|
>
|
|
{/* custom navbar */}
|
|
<View
|
|
className={classnames(
|
|
styles["custom-navbar"],
|
|
glass ? styles.glass : ""
|
|
)}
|
|
style={{
|
|
height: `${totalHeight}px`,
|
|
paddingTop: `${statusBarHeight}px`,
|
|
}}
|
|
>
|
|
<View className={styles["detail-navigator"]}>
|
|
<View
|
|
className={styles["detail-navigator-back"]}
|
|
onClick={handleBack}
|
|
>
|
|
<Image
|
|
className={styles["detail-navigator-back-icon"]}
|
|
src={ArrowLeft}
|
|
/>
|
|
</View>
|
|
{/* <View className={styles["detail-navigator-icon"]}>
|
|
<Image
|
|
className={styles["detail-navigator-logo-icon"]}
|
|
src={Logo}
|
|
/>
|
|
</View> */}
|
|
</View>
|
|
</View>
|
|
<View className={styles["detail-page-bg"]} style={backgroundImage} />
|
|
|
|
<View style={{ paddingTop: `${totalHeight}px` }}> </View>
|
|
{/* swiper */}
|
|
<Carousel detail={detail} />
|
|
{/* content */}
|
|
<View className={styles["detail-page-content"]}>
|
|
{/* avatar and tags */}
|
|
<GameTags
|
|
detail={detail}
|
|
userInfo={userInfo}
|
|
handleViewUserInfo={handleViewUserInfo}
|
|
/>
|
|
{/* title */}
|
|
<View className={styles["detail-page-content-title"]}>
|
|
<Text className={styles["detail-page-content-title-text"]}>
|
|
{detail.title}
|
|
</Text>
|
|
</View>
|
|
{/* Date and Place and weather */}
|
|
<GameInfo detail={detail} currentLocation={currentLocation} />
|
|
{/* detail */}
|
|
<VenueInfo detail={detail} />
|
|
{/* gameplay requirements */}
|
|
<GamePlayAndRequirement detail={detail} />
|
|
{/* participants */}
|
|
<Participants
|
|
detail={detail}
|
|
handleJoinGame={handleJoinGame}
|
|
handleViewUserInfo={handleViewUserInfo}
|
|
/>
|
|
{/* supplemental notes */}
|
|
<SupplementalNotes detail={detail} />
|
|
{/* organizer and recommend games by organizer */}
|
|
<OrganizerInfo
|
|
detail={detail}
|
|
userInfo={userInfo}
|
|
currentLocation={currentLocation}
|
|
onUpdateUserInfo={onUpdateUserInfo}
|
|
handleViewUserInfo={handleViewUserInfo}
|
|
handleAddComment={() => {
|
|
commentRef.current && commentRef.current.addComment();
|
|
}}
|
|
/>
|
|
<Comments
|
|
ref={commentRef}
|
|
game_id={Number(detail.id)}
|
|
message_id={message_id ? Number(message_id) : undefined}
|
|
publisher_id={Number(detail.publisher_id)}
|
|
/>
|
|
{/* sticky bottom action bar */}
|
|
<StickyBottom
|
|
handleShare={handleShare}
|
|
handleJoinGame={handleJoinGame}
|
|
detail={detail}
|
|
onStatusChange={onStatusChange}
|
|
handleAddComment={() => {
|
|
commentRef.current && commentRef.current.addComment();
|
|
}}
|
|
getCommentCount={
|
|
commentRef.current && commentRef.current.getCommentCount
|
|
}
|
|
currentUserInfo={myInfo}
|
|
/>
|
|
{/* share popup */}
|
|
<SharePopup
|
|
ref={sharePopupRef}
|
|
id={id as string}
|
|
from={from as string}
|
|
detail={detail}
|
|
userInfo={userInfo}
|
|
/>
|
|
</View>
|
|
</ScrollView>
|
|
);
|
|
}
|
|
|
|
export default Index;
|