239 lines
7.4 KiB
TypeScript
239 lines
7.4 KiB
TypeScript
import { useState, useEffect } from "react";
|
|
import React from "react";
|
|
import { View, Text, Image, ScrollView } from "@tarojs/components";
|
|
import { EmptyState } from "@/components";
|
|
import SubscribeNotificationTip from "@/components/SubscribeNotificationTip";
|
|
import noticeService from "@/services/noticeService";
|
|
import { formatRelativeTime } from "@/utils/timeUtils";
|
|
import Taro from "@tarojs/taro";
|
|
import { useGlobalState } from "@/store/global";
|
|
import { navigateTo } from "@/utils/navigation";
|
|
import { useReddotInfo, useFetchReddotInfo } from "@/store/messageStore";
|
|
import styles from "./MessagePageContent.module.scss";
|
|
|
|
interface MessageItem {
|
|
id: string;
|
|
notification_type: string;
|
|
title: string;
|
|
content: string;
|
|
create_time: string;
|
|
is_read: number;
|
|
related_user_avatar?: string;
|
|
related_user_nickname?: string;
|
|
activity_image?: string;
|
|
jump_url?: string;
|
|
}
|
|
|
|
type MessageCategory = "comment" | "follow";
|
|
|
|
interface MessagePageContentProps {
|
|
isActive?: boolean;
|
|
}
|
|
|
|
const MessagePageContent: React.FC<MessagePageContentProps> = ({ isActive = true }) => {
|
|
const { statusNavbarHeightInfo } = useGlobalState() || {};
|
|
const { totalHeight = 98 } = statusNavbarHeightInfo || {};
|
|
|
|
const [activeTab, setActiveTab] = useState<MessageCategory | null>(null);
|
|
const [messageList, setMessageList] = useState<MessageItem[]>([]);
|
|
const [loading, setLoading] = useState(false);
|
|
const [reachedBottom, setReachedBottom] = useState(false);
|
|
const [refreshing, setRefreshing] = useState(false);
|
|
const [hasLoaded, setHasLoaded] = useState(false); // 记录是否已经加载过数据
|
|
|
|
// 从 store 获取红点信息
|
|
const reddotInfo = useReddotInfo();
|
|
const fetchReddotInfo = useFetchReddotInfo();
|
|
|
|
const getNoticeList = async () => {
|
|
if (loading) return;
|
|
setLoading(true);
|
|
try {
|
|
const res = await noticeService.getNotificationList({});
|
|
if (res.code === 0) {
|
|
setMessageList(res.data.list || []);
|
|
}
|
|
} catch (e) {
|
|
(Taro as any).showToast({
|
|
title: "获取列表失败,请重试",
|
|
icon: "none",
|
|
duration: 2000,
|
|
});
|
|
} finally {
|
|
setLoading(false);
|
|
}
|
|
};
|
|
|
|
// 只有当页面激活且未加载过数据时才加载接口
|
|
useEffect(() => {
|
|
if (isActive && !hasLoaded) {
|
|
getNoticeList();
|
|
fetchReddotInfo();
|
|
setHasLoaded(true);
|
|
}
|
|
}, [isActive, hasLoaded]);
|
|
|
|
const filteredMessages = messageList;
|
|
|
|
const handleTabClick = (tab: MessageCategory) => {
|
|
if (tab === "comment") {
|
|
navigateTo({
|
|
url: "/other_pages/comment_reply/index",
|
|
});
|
|
return;
|
|
}
|
|
|
|
if (tab === "follow") {
|
|
navigateTo({
|
|
url: "/other_pages/new_follow/index",
|
|
});
|
|
return;
|
|
}
|
|
|
|
setActiveTab(activeTab === tab ? null : tab);
|
|
};
|
|
|
|
const handleViewDetail = (message: MessageItem) => {
|
|
if (!message.jump_url) {
|
|
console.log("暂无跳转链接");
|
|
return;
|
|
}
|
|
|
|
navigateTo({
|
|
url: message.jump_url,
|
|
}).catch(() => {
|
|
(Taro as any).showToast({
|
|
title: "页面不存在",
|
|
icon: "none",
|
|
duration: 2000,
|
|
});
|
|
});
|
|
};
|
|
|
|
const handleScrollToLower = () => {
|
|
if (!reachedBottom && filteredMessages.length > 0) {
|
|
setReachedBottom(true);
|
|
setTimeout(() => {
|
|
setReachedBottom(false);
|
|
}, 2000);
|
|
}
|
|
};
|
|
|
|
const handleRefresh = async () => {
|
|
setRefreshing(true);
|
|
try {
|
|
const res = await noticeService.getNotificationList({});
|
|
if (res.code === 0) {
|
|
setMessageList(res.data.list || []);
|
|
}
|
|
} catch (e) {
|
|
(Taro as any).showToast({
|
|
title: "刷新失败",
|
|
icon: "none",
|
|
duration: 2000,
|
|
});
|
|
} finally {
|
|
setRefreshing(false);
|
|
}
|
|
};
|
|
|
|
return (
|
|
<View className={styles.messageContainer} style={{ paddingTop: `${totalHeight}px` }}>
|
|
<View className={styles.categoryTabs}>
|
|
<View
|
|
className={`${styles.tabItem} ${activeTab === "comment" ? styles.active : ""}`}
|
|
onClick={() => handleTabClick("comment")}
|
|
>
|
|
<View className={styles.tabIconWrapper}>
|
|
<Image
|
|
className={styles.tabIcon}
|
|
src={require('@/static/message/comment-icon.svg')}
|
|
mode="aspectFit"
|
|
/>
|
|
{(reddotInfo?.comment_unread_count || 0) > 0 && (
|
|
<View className={styles.badge}>
|
|
{`+${(reddotInfo?.comment_unread_count || 0) > 99 ? 99 : reddotInfo?.comment_unread_count}`}
|
|
</View>
|
|
)}
|
|
</View>
|
|
<Text className={styles.tabText}>评论和回复</Text>
|
|
</View>
|
|
<View
|
|
className={`${styles.tabItem} ${activeTab === "follow" ? styles.active : ""}`}
|
|
onClick={() => handleTabClick("follow")}
|
|
>
|
|
<View className={styles.tabIconWrapper}>
|
|
<Image
|
|
className={styles.tabIcon}
|
|
src={require('@/static/message/follow-icon.svg')}
|
|
mode="aspectFit"
|
|
/>
|
|
{(reddotInfo?.follow_unread_count || 0) > 0 && (
|
|
<View className={styles.badge}>
|
|
{`+${(reddotInfo?.follow_unread_count || 0) > 99 ? 99 : reddotInfo?.follow_unread_count}`}
|
|
</View>
|
|
)}
|
|
</View>
|
|
<Text className={styles.tabText}>新增关注</Text>
|
|
</View>
|
|
</View>
|
|
|
|
{/* 通知提示框 */}
|
|
<View className={styles.notificationTipWrapper}>
|
|
<SubscribeNotificationTip />
|
|
</View>
|
|
|
|
<ScrollView
|
|
scrollY
|
|
refresherBackground="#FAFAFA"
|
|
className={styles.messageScroll}
|
|
scrollWithAnimation
|
|
enhanced
|
|
showScrollbar={false}
|
|
lowerThreshold={50}
|
|
onScrollToLower={handleScrollToLower}
|
|
refresherEnabled={true}
|
|
refresherTriggered={refreshing}
|
|
onRefresherRefresh={handleRefresh}
|
|
>
|
|
{filteredMessages.length > 0 ? (
|
|
<View className={styles.messageCards}>
|
|
{filteredMessages.map((message) => (
|
|
<View className={styles.messageCard} key={message.id} onClick={() => handleViewDetail(message)}>
|
|
<View className={styles.cardTitleRow}>
|
|
<Text className={styles.cardTitle}>{message.title}</Text>
|
|
</View>
|
|
<View className={styles.cardTimeRow}>
|
|
<Text className={styles.cardTime}>{formatRelativeTime(message.create_time)}</Text>
|
|
</View>
|
|
<View className={styles.cardContentRow}>
|
|
<Text className={styles.cardContent}>{message.content}</Text>
|
|
</View>
|
|
<View className={styles.cardFooter}>
|
|
<View className={styles.footerDivider}></View>
|
|
<View className={styles.footerAction}>
|
|
<Text className={styles.actionText}>查看详情</Text>
|
|
<View className={styles.actionArrow}>
|
|
<Image className={styles.img} src={require('@/static/message/ar-right.svg')} ></Image>
|
|
</View>
|
|
</View>
|
|
</View>
|
|
</View>
|
|
))}
|
|
{filteredMessages.length > 0 && (
|
|
<View className={styles.bottomTip}>
|
|
<Text className={styles.tipText}>到底了</Text>
|
|
</View>
|
|
)}
|
|
</View>
|
|
) : (
|
|
<EmptyState text="暂无消息" />
|
|
)}
|
|
</ScrollView>
|
|
</View>
|
|
);
|
|
};
|
|
|
|
export default MessagePageContent;
|
|
|