2025-08-01 14:06:24 +08:00

234 lines
7.0 KiB
TypeScript

import ConversationsSvg from '@/assets/icons/svg/conversations.svg';
import StoriesSvg from '@/assets/icons/svg/stories.svg';
import AskNavbar from '@/components/layout/ask';
import CarouselComponent from '@/components/owner/carousel';
import CreateCountComponent from '@/components/owner/createCount';
import Ranking from '@/components/owner/ranking';
import MemberCard from '@/components/owner/rights/memberCard';
import SettingModal from '@/components/owner/setting';
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();
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);
const getUserInfo = () => {
fetchApi("/membership/personal-center-info").then((res) => {
setUserInfoDetails(res as UserInfoDetails);
})
}
// 设计轮询获取数量统计
useFocusEffect(
useCallback(() => {
// 当页面获取焦点时开始轮询
const interval = setInterval(() => {
getCountData();
}, 5000);
// 立即执行一次
getCountData();
// 当页面失去焦点时清除定时器
return () => clearInterval(interval);
}, []) // 空依赖数组,因为 getCountData 是稳定的
);
// 初始化获取用户信息
useEffect(() => {
getUserInfo();
}, []);
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} />
)}
{/* 导航栏 */}
<AskNavbar />
</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',
},
});