266 lines
7.8 KiB
TypeScript
266 lines
7.8 KiB
TypeScript
import ConversationsSvg from '@/assets/icons/svg/conversations.svg';
|
||
import StoriesSvg from '@/assets/icons/svg/stories.svg';
|
||
|
||
import CreateCountComponent from '@/components/owner/createCount';
|
||
import MemberCard from '@/components/owner/rights/memberCard';
|
||
import SettingModal from '@/components/owner/setting';
|
||
import SkeletonOwner from '@/components/owner/SkeletonOwner';
|
||
import UserInfo from '@/components/owner/userName';
|
||
import { checkAuthStatus } from '@/lib/auth';
|
||
import { fetchApi } from '@/lib/server-api-util';
|
||
import { CountData, UserInfoDetails } from '@/types/user';
|
||
import { useFocusEffect, usePathname, useRouter } from 'expo-router';
|
||
import { useCallback, useEffect, useState } from 'react';
|
||
import { useTranslation } from 'react-i18next';
|
||
import { FlatList, StyleSheet, View } from 'react-native';
|
||
import { useSafeAreaInsets } from "react-native-safe-area-context";
|
||
|
||
export default function OwnerPage() {
|
||
const insets = useSafeAreaInsets();
|
||
const { t } = useTranslation();
|
||
const router = useRouter();
|
||
const pathname = usePathname();
|
||
|
||
// 添加页面挂载状态
|
||
const [isMounted, setIsMounted] = useState(false);
|
||
|
||
useEffect(() => {
|
||
const checkAuth = async () => {
|
||
const authStatus = await checkAuthStatus(router);
|
||
if (!authStatus) {
|
||
router.push('/login');
|
||
}
|
||
};
|
||
checkAuth();
|
||
}, [router]);
|
||
|
||
// 设置弹窗
|
||
const [modalVisible, setModalVisible] = useState(false);
|
||
|
||
|
||
// 数据统计
|
||
const [countData, setCountData] = useState<CountData>({} as CountData);
|
||
|
||
// 获取数量统计 --- 需要轮询
|
||
const getCountData = () => {
|
||
fetchApi("/material/statistics").then((res) => {
|
||
setCountData(res as CountData);
|
||
});
|
||
|
||
}
|
||
|
||
// 获取用户信息
|
||
const [userInfoDetails, setUserInfoDetails] = useState<UserInfoDetails>({} as UserInfoDetails);
|
||
|
||
// 优化getUserInfo函数,添加挂载状态检查
|
||
const getUserInfo = useCallback(() => {
|
||
fetchApi("/membership/personal-center-info").then((res) => {
|
||
// 只有在组件挂载时才更新状态
|
||
if (isMounted) {
|
||
setUserInfoDetails(res as UserInfoDetails);
|
||
}
|
||
})
|
||
}, [isMounted]);
|
||
|
||
// 设计轮询获取数量统计
|
||
useFocusEffect(
|
||
useCallback(() => {
|
||
// 当页面获取焦点时开始轮询
|
||
const interval = setInterval(() => {
|
||
getCountData();
|
||
}, 5000);
|
||
|
||
// 立即执行一次
|
||
getCountData();
|
||
|
||
// 当页面失去焦点时清除定时器
|
||
return () => clearInterval(interval);
|
||
}, []) // 空依赖数组,因为 getCountData 是稳定的
|
||
);
|
||
|
||
// 初始化获取用户信息
|
||
useEffect(() => {
|
||
let isActive = true;
|
||
|
||
const initialize = async () => {
|
||
try {
|
||
await getUserInfo();
|
||
} catch (error) {
|
||
console.error('初始化失败:', error);
|
||
} finally {
|
||
if (isActive) {
|
||
setIsMounted(true);
|
||
}
|
||
}
|
||
};
|
||
|
||
initialize();
|
||
|
||
return () => {
|
||
isActive = false;
|
||
};
|
||
}, [getUserInfo]);
|
||
|
||
// 如果组件未完全加载,显示骨架屏
|
||
if (!isMounted) {
|
||
return (
|
||
<View style={[styles.container, { paddingTop: insets.top }]}>
|
||
<SkeletonOwner />
|
||
</View>
|
||
);
|
||
}
|
||
|
||
return (
|
||
<View style={[styles.container, { paddingTop: insets.top }]}>
|
||
<FlatList
|
||
data={[]} // 空数据,因为我们只需要渲染一次
|
||
renderItem={null} // 不需要渲染项目
|
||
contentContainerStyle={styles.contentContainer}
|
||
showsVerticalScrollIndicator={false}
|
||
ListHeaderComponent={
|
||
<View style={{ gap: 16 }}>
|
||
{/* 用户信息 */}
|
||
<UserInfo userInfo={userInfoDetails} />
|
||
|
||
{/* 会员卡 */}
|
||
<MemberCard pro={userInfoDetails?.membership_level} />
|
||
|
||
{/* 分类 */}
|
||
{/* <View style={{ marginHorizontal: -16, marginBottom: -16 }}>
|
||
<CarouselComponent data={userInfoDetails?.material_counter} />
|
||
</View> */}
|
||
|
||
{/* 作品数据 */}
|
||
<View className='flex flex-row justify-between gap-[1rem]'>
|
||
<CreateCountComponent title={t("generalSetting.storiesCreated", { ns: "personal" })} icon={<StoriesSvg width={30} height={30} />} number={userInfoDetails.stories_count} />
|
||
<CreateCountComponent title={t("generalSetting.conversationsWithMemo", { ns: "personal" })} icon={<ConversationsSvg width={30} height={30} />} number={userInfoDetails.conversations_count} />
|
||
</View>
|
||
|
||
{/* 排行榜 */}
|
||
{/* <Ranking data={userInfoDetails.title_rankings} /> */}
|
||
</View>
|
||
}
|
||
// 优化性能:添加 getItemLayout
|
||
getItemLayout={(data, index) => (
|
||
{ length: 1000, offset: 1000 * index, index }
|
||
)}
|
||
/>
|
||
{/* 设置弹窗 - 使用条件渲染避免层级冲突 */}
|
||
{modalVisible && (
|
||
<SettingModal modalVisible={modalVisible} setModalVisible={setModalVisible} userInfo={userInfoDetails.user_info} />
|
||
)}
|
||
</View>
|
||
);
|
||
}
|
||
|
||
const styles = StyleSheet.create({
|
||
container: {
|
||
flex: 1,
|
||
backgroundColor: 'white',
|
||
paddingBottom: 86,
|
||
},
|
||
contentContainer: {
|
||
paddingHorizontal: 16,
|
||
},
|
||
resourceContainer: {
|
||
flexDirection: 'row',
|
||
alignItems: 'center',
|
||
justifyContent: 'space-between',
|
||
backgroundColor: "#4C320C",
|
||
paddingVertical: 8,
|
||
paddingHorizontal: 32,
|
||
borderRadius: 18,
|
||
},
|
||
text: {
|
||
fontSize: 12,
|
||
fontWeight: '700',
|
||
color: '#FFB645',
|
||
},
|
||
secondText: {
|
||
fontSize: 16,
|
||
fontWeight: '700',
|
||
color: '#fff',
|
||
},
|
||
userInfo: {
|
||
flexDirection: 'row',
|
||
alignItems: 'center',
|
||
padding: 16,
|
||
},
|
||
medal: {
|
||
marginLeft: 16,
|
||
},
|
||
backButton: {
|
||
padding: 4,
|
||
},
|
||
headerTitle: {
|
||
fontSize: 18,
|
||
fontWeight: '600',
|
||
color: '#333',
|
||
},
|
||
content: {
|
||
flex: 1,
|
||
},
|
||
profileSection: {
|
||
backgroundColor: '#fff',
|
||
padding: 20,
|
||
flexDirection: 'row',
|
||
alignItems: 'center',
|
||
marginBottom: 10,
|
||
},
|
||
avatarContainer: {
|
||
marginRight: 16,
|
||
},
|
||
avatar: {
|
||
width: 70,
|
||
height: 70,
|
||
borderRadius: 35,
|
||
borderWidth: 2,
|
||
borderColor: '#FFD38D',
|
||
},
|
||
profileInfo: {
|
||
flex: 1,
|
||
},
|
||
userName: {
|
||
fontSize: 18,
|
||
fontWeight: '600',
|
||
color: '#333',
|
||
marginBottom: 4,
|
||
},
|
||
userPhone: {
|
||
fontSize: 14,
|
||
color: '#666',
|
||
},
|
||
editButton: {
|
||
flexDirection: 'row',
|
||
alignItems: 'center',
|
||
padding: 8,
|
||
borderWidth: 1,
|
||
borderColor: '#eee',
|
||
borderRadius: 15,
|
||
},
|
||
editButtonText: {
|
||
marginLeft: 4,
|
||
color: '#666',
|
||
fontSize: 14,
|
||
},
|
||
menuContainer: {
|
||
backgroundColor: '#fff',
|
||
paddingHorizontal: 16,
|
||
},
|
||
menuItem: {
|
||
flexDirection: 'row',
|
||
alignItems: 'center',
|
||
paddingVertical: 16,
|
||
borderBottomWidth: 1,
|
||
borderBottomColor: '#f5f5f5',
|
||
},
|
||
menuItemText: {
|
||
flex: 1,
|
||
marginLeft: 12,
|
||
fontSize: 16,
|
||
color: '#333',
|
||
},
|
||
arrowIcon: {
|
||
marginLeft: 'auto',
|
||
},
|
||
}); |