import { Ionicons } from '@expo/vector-icons'; import { LinearGradient } from 'expo-linear-gradient'; import { useRouter } from 'expo-router'; import { ActivityIndicator, Pressable, ScrollView, StyleSheet, Text, View, } from 'react-native'; import { SafeAreaView } from 'react-native-safe-area-context'; import { useProfileData } from '../../src/hooks'; import { colors } from '../../src/theme'; import type { Badge, DimensionScore, JobPreference } from '../../src/types'; /* ===================== 展示层映射(全部使用主题令牌) ===================== */ /** 维度等级 → 展示配置(优秀=品牌蓝,良好=灰色) */ const DIMENSION_LEVEL: Record< DimensionScore['level'], { label: string; bar: string; bg: string; text: string } > = { excellent: { label: '优秀', bar: colors.primary, bg: colors.primaryLight, text: colors.primaryDark }, good: { label: '良好', bar: colors.textHint, bg: colors.pageBg, text: colors.textSecondary }, }; /** 求职偏好字段 → 展示标签 */ const PREF_ITEMS: { key: keyof JobPreference; label: string }[] = [ { key: 'position', label: '期望职位' }, { key: 'city', label: '期望城市' }, { key: 'salary', label: '期望薪资' }, { key: 'workType', label: '工作类型' }, { key: 'status', label: '求职状态' }, ]; /* ===================== 子组件 ===================== */ /** 单个维度评分行(横向评分条) */ function DimensionRow({ dimension }: { dimension: DimensionScore }) { const theme = DIMENSION_LEVEL[dimension.level]; return ( {dimension.name} {dimension.score} {theme.label} ); } /** 单个勋章卡片(已获得=彩色,未获得=灰色+进度条) */ function BadgeCard({ badge }: { badge: Badge }) { return ( {badge.icon} {badge.title} {badge.description} {badge.obtained ? ( 已获得 ) : ( <> {badge.progress}/{badge.target} )} ); } /** * 我的页 */ export default function ProfileScreen() { const { profile, overallScore, dimensions, preference, badges, loading, error, refresh } = useProfileData(); const router = useRouter(); // 错误态 if (error) { return ( 加载失败,请重试 重试 ); } // 加载态 if (loading || !profile || !overallScore || !preference) { return ( ); } return ( {/* 顶部渐变头部:标题 + 用户信息(随页面滚动) */} 我的 router.push('/settings')} hitSlop={8}> {profile.avatar} {profile.name} {profile.bio} {/* 内容区 */} {/* 综合评分卡片 */} {overallScore.score} 分 {overallScore.level} {overallScore.rank} {/* 八大维度评分 */} 八大维度评分 console.log('评分申诉')} hitSlop={6}> 评分申诉 {dimensions.map((dimension) => ( ))} {/* 求职偏好 */} 求职偏好 console.log('编辑求职偏好')} hitSlop={6}> 编辑 {PREF_ITEMS.map(({ key, label }, index) => { const value = preference[key]; const isLast = index === PREF_ITEMS.length - 1; const isStatus = key === 'status'; return ( console.log(`编辑${label}`)} > {label} {isStatus ? ( {value} ) : ( {value} )} ); })} {/* 全部勋章 */} 全部勋章 {badges.map((badge) => ( ))} ); } // 跨平台阴影 const shadow = { shadowColor: colors.textPrimary, shadowOffset: { width: 0, height: 2 }, shadowOpacity: 0.06, shadowRadius: 8, elevation: 3, }; const styles = StyleSheet.create({ safeArea: { flex: 1, backgroundColor: colors.pageBg, }, stateWrap: { flex: 1, alignItems: 'center', justifyContent: 'center', }, stateText: { marginTop: 12, fontSize: 14, color: colors.textSecondary, }, retryBtn: { marginTop: 16, paddingHorizontal: 24, paddingVertical: 8, borderRadius: 18, backgroundColor: colors.primaryBtn, }, retryText: { fontSize: 13, fontWeight: '600', color: colors.white, }, /* ---- 顶部渐变头部 ---- */ headerGradient: { paddingHorizontal: 20, paddingTop: 8, paddingBottom: 24, borderBottomLeftRadius: 24, borderBottomRightRadius: 24, }, headerRow: { height: 40, flexDirection: 'row', alignItems: 'center', justifyContent: 'space-between', }, headerTitle: { fontSize: 17, fontWeight: '700', color: colors.white, }, profileRow: { flexDirection: 'row', alignItems: 'center', marginTop: 8, }, avatar: { width: 60, height: 60, borderRadius: 30, backgroundColor: colors.white, alignItems: 'center', justifyContent: 'center', }, avatarText: { fontSize: 26, fontWeight: '700', color: colors.primary, }, profileInfo: { marginLeft: 14, }, userName: { fontSize: 20, fontWeight: '700', color: colors.white, }, bio: { marginTop: 6, fontSize: 13, color: colors.white, opacity: 0.85, }, /* ---- 内容区 ---- */ scroll: { flex: 1, }, scrollContent: { paddingBottom: 24, }, content: { paddingHorizontal: 20, paddingTop: 16, }, /* ---- 综合评分卡片 ---- */ scoreCard: { flexDirection: 'row', alignItems: 'center', backgroundColor: colors.white, borderRadius: 16, paddingHorizontal: 20, paddingVertical: 20, ...shadow, }, scoreValue: { fontSize: 40, fontWeight: '700', color: colors.primaryDark, }, scoreUnit: { fontSize: 16, fontWeight: '600', color: colors.primaryDark, }, scoreTag: { marginLeft: 12, backgroundColor: colors.primaryLight, paddingHorizontal: 10, paddingVertical: 4, borderRadius: 12, }, scoreTagText: { fontSize: 13, fontWeight: '600', color: colors.primaryDark, }, scoreRank: { flex: 1, textAlign: 'right', marginLeft: 12, fontSize: 13, color: colors.textSecondary, }, /* ---- 分区标题 ---- */ sectionHeader: { flexDirection: 'row', alignItems: 'center', marginTop: 24, marginBottom: 12, }, sectionBar: { width: 4, height: 16, borderRadius: 2, backgroundColor: colors.primary, marginRight: 8, }, sectionTitle: { fontSize: 18, fontWeight: '700', color: colors.textPrimary, }, sectionTitleGrow: { flex: 1, }, sectionLink: { fontSize: 13, color: colors.primary, }, /* ---- 八大维度(横向评分条) ---- */ dimCard: { backgroundColor: colors.white, borderRadius: 16, paddingHorizontal: 16, paddingVertical: 6, ...shadow, }, dimRow: { flexDirection: 'row', alignItems: 'center', paddingVertical: 12, }, dimName: { width: 78, fontSize: 13, color: colors.textSecondary, }, dimTrack: { flex: 1, height: 6, borderRadius: 3, backgroundColor: colors.border, marginHorizontal: 12, }, dimFill: { height: 6, borderRadius: 3, }, dimScore: { width: 28, textAlign: 'right', fontSize: 14, fontWeight: '700', color: colors.textPrimary, }, levelTag: { marginLeft: 10, paddingHorizontal: 8, paddingVertical: 2, borderRadius: 10, }, levelTagText: { fontSize: 11, fontWeight: '600', }, /* ---- 求职偏好 ---- */ prefCard: { backgroundColor: colors.white, borderRadius: 16, paddingHorizontal: 16, paddingVertical: 6, ...shadow, }, prefRow: { flexDirection: 'row', alignItems: 'center', justifyContent: 'space-between', paddingVertical: 12, borderBottomWidth: 1, borderBottomColor: colors.borderLight, }, prefRowLast: { borderBottomWidth: 0, }, prefLabel: { fontSize: 14, color: colors.textSecondary, }, prefValue: { fontSize: 14, fontWeight: '600', color: colors.textPrimary, }, prefStatus: { flexDirection: 'row', alignItems: 'center', }, prefStatusDot: { width: 8, height: 8, borderRadius: 4, backgroundColor: colors.success, marginRight: 6, }, prefStatusText: { fontSize: 14, fontWeight: '600', color: colors.successText, }, /* ---- 全部勋章 ---- */ hScroll: { flexGrow: 0, marginHorizontal: -20, }, hScrollContent: { paddingHorizontal: 20, gap: 12, }, badgeCard: { width: 140, backgroundColor: colors.white, borderRadius: 16, padding: 16, alignItems: 'center', ...shadow, }, badgeIcon: { fontSize: 32, }, badgeIconLocked: { opacity: 0.35, }, badgeTitle: { marginTop: 10, fontSize: 14, fontWeight: '700', color: colors.textPrimary, }, badgeTitleLocked: { color: colors.textHint, }, badgeDesc: { marginTop: 4, fontSize: 12, color: colors.textSecondary, textAlign: 'center', }, badgeObtainedTag: { marginTop: 10, backgroundColor: colors.successLight, paddingHorizontal: 10, paddingVertical: 3, borderRadius: 10, }, badgeObtainedText: { fontSize: 11, fontWeight: '600', color: colors.successText, }, badgeProgressTrack: { width: '100%', height: 4, borderRadius: 2, backgroundColor: colors.border, marginTop: 12, }, badgeProgressFill: { height: 4, borderRadius: 2, backgroundColor: colors.primary, }, badgeProgressText: { marginTop: 6, fontSize: 11, color: colors.textHint, }, });