jinyaqiu 828e84710f
All checks were successful
Dev Deploy / Explore-Gitea-Actions (push) Successful in 24s
feat: 个人中心
2025-07-14 10:42:59 +08:00

182 lines
7.3 KiB
TypeScript

import ArrowSvg from '@/assets/icons/svg/arrow.svg';
import ReturnArrowSvg from '@/assets/icons/svg/returnArrow.svg';
import { CascaderItem } from '@/components/cascader';
import ClassifyModal from '@/components/owner/classify';
import LocationModal from '@/components/owner/location';
import PodiumComponent from '@/components/owner/podium';
import RankList from '@/components/owner/rankList';
import { ThemedText } from '@/components/ThemedText';
import { transformData } from '@/components/utils/objectToCascader';
import { fetchApi } from '@/lib/server-api-util';
import { GroupedData, RankingItem, TargetItem } from '@/types/user';
import { useRouter } from "expo-router";
import { useCallback, useEffect, useRef, useState } from 'react';
import { LayoutChangeEvent, StyleSheet, TouchableOpacity, View } from 'react-native';
import { useSafeAreaInsets } from "react-native-safe-area-context";
export default function OwnerPage() {
const insets = useSafeAreaInsets();
const router = useRouter();
// 位置弹窗
const [locationModalVisible, setLocationModalVisible] = useState(false);
// 分类弹窗
const [classifyModalVisible, setClassifyModalVisible] = useState(false);
// 在组件内部添加:
const podiumRef = useRef<View>(null);
const [podiumPosition, setPodiumPosition] = useState({ x: 0, y: 0, width: 0, height: 0 });
// 获取分类
const [classify, setClassify] = useState<TargetItem[]>([]);
const getClassify = () => {
fetchApi<GroupedData>("/title-tags").then((res: GroupedData) => {
setClassify(transformData(res));
});
}
// 选择地区
const [selectedLocation, setSelectedLocation] = useState<any>();
// 选择分类
const [selectedClassify, setSelectedClassify] = useState<any>();
const onPodiumLayout = (event: LayoutChangeEvent) => {
if (podiumRef.current) {
podiumRef.current.measure((x, y, width, height, pageX, pageY) => {
setPodiumPosition({
x: pageX,
y: pageY,
width,
height
});
});
}
};
// 地区选择
const handleLocationChange = useCallback((selectedItems: CascaderItem[]) => {
console.log('SelectedLocation:', selectedItems);
if (selectedItems.length > 0) {
const lastItem = selectedItems[selectedItems.length - 1];
// 只有当选择完成时才更新状态
if (!lastItem.children || lastItem.children.length === 0) {
setSelectedLocation(selectedItems);
}
}
}, []);
// 分类选择
const handleClassifyChange = useCallback((selectedItems: CascaderItem[]) => {
console.log('SelectedClassify:', selectedItems);
if (selectedItems.length > 0) {
const lastItem = selectedItems[selectedItems.length - 1];
// 只有当选择完成时才更新状态
if (!lastItem.children || lastItem.children.length === 0) {
setSelectedClassify(selectedItems);
}
}
}, []);
// 获取排名信息
const [ranking, setRanking] = useState<RankingItem[]>([]);
const getRanking = () => {
fetchApi<RankingItem[]>("/title-rank", {
method: "POST",
body: JSON.stringify({
"title_tag_id": selectedClassify?.length > 0 ? selectedClassify[selectedClassify?.length - 1].value : 3,
"area_id": 1
})
}).then((res) => {
setRanking(res);
});
}
// 当用户选择发生变化时,重新获取排名
useEffect(() => {
getRanking();
}, [selectedLocation, selectedClassify])
// 初始化获取分类
useEffect(() => {
getClassify();
}, [])
return (
<View style={[styles.container, { paddingTop: insets.top }]}>
{/* 导航栏 */}
<View
style={styles.header}
ref={podiumRef}
onLayout={onPodiumLayout}
>
<TouchableOpacity onPress={() => { router.push('/owner') }} style={{ padding: 16 }}>
<ReturnArrowSvg />
</TouchableOpacity>
<ThemedText style={styles.headerTitle}>
Top Memory Makers
</ThemedText>
<View className='opacity-0'>123</View>
</View>
<View style={{ display: 'flex', flexDirection: 'row', alignItems: 'center', gap: 16, marginHorizontal: 16 }}>
<TouchableOpacity onPress={() => { setLocationModalVisible(true) }} style={{ display: 'flex', flexDirection: 'row', alignItems: 'center', gap: 8 }}>
<ThemedText style={{ color: selectedLocation?.length > 0 ? '#FFB645' : '#4C320C' }}>
{selectedLocation?.length > 0 ? selectedLocation[selectedLocation?.length - 1].name : "地区"}
</ThemedText>
{
selectedLocation?.length > 0
?
<ArrowSvg style={{ transform: [{ rotate: '90deg' }], width: 12, height: 12 }} />
:
<ReturnArrowSvg style={{ transform: [{ rotate: '270deg' }], width: 12, height: 12 }} />
}
</TouchableOpacity>
<TouchableOpacity onPress={() => { setClassifyModalVisible(true) }} style={{ display: 'flex', flexDirection: 'row', alignItems: 'center', gap: 8 }}>
<ThemedText style={{ color: selectedClassify?.length > 0 ? '#FFB645' : '#4C320C' }}>
{selectedClassify?.length > 0 ? selectedClassify[selectedClassify?.length - 1].name : "分类"}
</ThemedText>
{selectedClassify?.length > 0
?
<ArrowSvg style={{ transform: [{ rotate: '90deg' }], width: 12, height: 12 }} />
:
<ReturnArrowSvg style={{ transform: [{ rotate: '270deg' }], width: 12, height: 12 }} />
}
</TouchableOpacity>
</View>
{/* 颁奖台 */}
<PodiumComponent data={ranking} />
{/* 排名区域 */}
<RankList data={ranking} />
{/* 地区选择弹窗 */}
<LocationModal
modalVisible={locationModalVisible}
setModalVisible={setLocationModalVisible}
podiumPosition={podiumPosition}
handleChange={handleLocationChange}
/>
{/* 分类选择弹窗 */}
<ClassifyModal
data={classify}
modalVisible={classifyModalVisible}
setModalVisible={setClassifyModalVisible}
podiumPosition={podiumPosition}
handleChange={handleClassifyChange}
/>
</View>
);
}
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: 'white',
},
header: {
display: 'flex',
flexDirection: 'row',
justifyContent: 'space-between',
alignItems: 'center',
marginVertical: 16,
},
headerTitle: {
fontSize: 20,
fontWeight: '700',
color: '#4C320C',
}
});