Files
mini-programs/src/other_pages/new_follow/index.tsx
2026-02-07 11:56:43 +08:00

264 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 { useState, useEffect } from "react";
import { View, Text, ScrollView, Image } from "@tarojs/components";
import { withAuth, EmptyState, GeneralNavbar } from "@/components";
import { useGlobalState } from "@/store/global";
import FollowService from "@/services/followService";
import messageService from "@/services/messageService";
import { formatShortRelativeTime } from "@/utils/timeUtils";
import Taro from "@tarojs/taro";
import "./index.scss";
// 关注项类型定义
interface FollowItem {
id: number;
user_id: number;
user_avatar: string;
user_nickname: string;
user_signature?: string;
city?: string;
ntrp_level?: string;
time: string;
is_mutual: boolean; // 是否互相关注
}
const NewFollow = () => {
const [followList, setFollowList] = useState<FollowItem[]>([]);
const [loading, setLoading] = useState(false);
const [refreshing, setRefreshing] = useState(false);
const { statusNavbarHeightInfo } = useGlobalState() || {};
const { totalHeight = 98 } = statusNavbarHeightInfo || {};
useEffect(() => {
getFollowList();
}, []);
// 获取新增关注列表
const getFollowList = async () => {
if (loading) return;
setLoading(true);
try {
const res = await FollowService.get_new_fans_list(1, 20);
if (res.list && res.list.length > 0) {
// 映射数据
const mappedList = res.list.map((item: any) => ({
id: item.id,
user_id: item.id,
user_avatar: item.avatar_url || "",
user_nickname: item.nickname || "匿名用户",
user_signature: item.personal_profile || "",
city: item.city || "",
ntrp_level: item.ntrp_level || "",
time: item.follow_time,
is_mutual: item.is_mutual || false,
}));
setFollowList(mappedList);
// 获取所有关注者ID列表并标记已读传入所有ID包括已读和未读
const allFanIds = res.list.map((item: any) => item.id);
if (allFanIds.length > 0) {
// 使用统一接口标记已读传入所有关注者ID
messageService.markAsRead('follow', allFanIds).catch(e => {
console.error("标记关注已读失败:", e);
});
}
} else {
// 如果没有数据,设置为空数组以显示空状态
setFollowList([]);
}
} catch (e) {
Taro.showToast({
title: "获取列表失败",
icon: "none",
duration: 2000,
});
} finally {
setLoading(false);
}
};
// 处理回关/取消关注
const handleFollowBack = async (item: FollowItem) => {
try {
if (item.is_mutual) {
// 已经互相关注,点击取消关注
await FollowService.unfollow_user(item.user_id);
Taro.showToast({
title: "取消关注成功",
icon: "success",
duration: 2000,
});
// 更新列表
setFollowList(prevList =>
prevList.map(followItem =>
followItem.id === item.id
? { ...followItem, is_mutual: false }
: followItem
)
);
} else {
// 未互关,点击回关
await FollowService.follow_back(item.user_id);
Taro.showToast({
title: "关注成功",
icon: "success",
duration: 2000,
});
// 更新列表
setFollowList(prevList =>
prevList.map(followItem =>
followItem.id === item.id
? { ...followItem, is_mutual: true }
: followItem
)
);
}
} catch (e) {
Taro.showToast({
title: item.is_mutual ? "取消关注失败" : "关注失败",
icon: "none",
duration: 2000,
});
}
};
// 处理返回
const handleBack = () => {
Taro.navigateBack();
};
// 处理点击用户
const handleUserClick = (userId: number) => {
Taro.navigateTo({
url: `/user_pages/other/index?userid=${userId}`,
});
};
// 处理下拉刷新
const handleRefresh = async () => {
setRefreshing(true);
try {
const res = await FollowService.get_new_fans_list(1, 20);
if (res.list && res.list.length > 0) {
const mappedList = res.list.map((item: any) => ({
id: item.id,
user_id: item.id,
user_avatar: item.avatar_url || "",
user_nickname: item.nickname || "匿名用户",
user_signature: item.personal_profile || "",
city: item.city || "",
ntrp_level: item.ntrp_level || "",
time: item.follow_time,
is_mutual: item.is_mutual || false,
}));
setFollowList(mappedList);
// 获取所有关注者ID列表并标记已读传入所有ID
const allFanIds = res.list.map((item: any) => item.id);
if (allFanIds.length > 0) {
messageService.markAsRead('follow', allFanIds).catch(e => {
console.error("标记关注已读失败:", e);
});
}
} else {
// 如果没有数据,设置为空数组以显示空状态
setFollowList([]);
}
} catch (e) {
Taro.showToast({
title: "刷新失败",
icon: "none",
duration: 2000,
});
} finally {
setRefreshing(false);
}
};
// 渲染关注项
const renderFollowItem = (item: FollowItem) => {
return (
<View className="follow-item" key={item.id}>
<View className="follow-left" onClick={() => handleUserClick(item.user_id)}>
<Image
className="user-avatar" mode="aspectFill"
src={item.user_avatar || require("@/static/userInfo/default_avatar.svg")}
/>
<View className="user-info">
<Text className="user-nickname">{item.user_nickname}</Text>
{item.user_signature ? (
<Text className="user-signature">{item.user_signature}</Text>
) : (
<View className="action-row">
<Text className="action-text">{formatShortRelativeTime(item.time)}</Text>
</View>
)}
</View>
</View>
<View
className={`follow-button ${item.is_mutual ? "mutual" : ""}`}
onClick={() => handleFollowBack(item)}
>
<Text className="button-text">{item.is_mutual ? "互相关注" : "回关"}</Text>
</View>
</View>
);
};
return (
<View className="new-follow-container">
{/* 顶部导航栏 */}
<GeneralNavbar
title="新增关注"
showBack={true}
showAvatar={false}
onBack={handleBack}
/>
{/* 关注列表 */}
<ScrollView
scrollY
className="follow-scroll"
style={{ paddingTop: `${totalHeight}px` }}
scrollWithAnimation
enhanced
showScrollbar={false}
refresherEnabled={true}
refresherBackground="#FAFAFA"
refresherTriggered={refreshing}
onRefresherRefresh={handleRefresh}
>
{!loading && followList.length > 0 ? (
<View className="follow-list">
{followList.map(renderFollowItem)}
{/* 到底了提示 */}
<View className="bottom-tip">
<Text className="tip-text"></Text>
</View>
</View>
) : !loading ? (
<EmptyState text="暂无新增关注" />
) : null}
</ScrollView>
</View>
);
};
export default withAuth(NewFollow);