232 lines
6.9 KiB
TypeScript
232 lines
6.9 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 CreateCountComponent from '@/components/owner/createCount';
|
|
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',
|
|
},
|
|
}); |