feat: 新增健康档案模块,支持家庭邀请与个人健康数据管理
This commit is contained in:
@@ -23,11 +23,11 @@ type TabConfig = {
|
||||
};
|
||||
|
||||
const TAB_CONFIGS: Record<string, TabConfig> = {
|
||||
statistics: { icon: 'chart.pie.fill', titleKey: 'statistics.tabs.health' },
|
||||
medications: { icon: 'pills.fill', titleKey: 'statistics.tabs.medications' },
|
||||
fasting: { icon: 'timer', titleKey: 'statistics.tabs.fasting' },
|
||||
challenges: { icon: 'trophy.fill', titleKey: 'statistics.tabs.challenges' },
|
||||
personal: { icon: 'person.fill', titleKey: 'statistics.tabs.personal' },
|
||||
statistics: { icon: 'chart.pie.fill', titleKey: 'health.tabs.health' },
|
||||
medications: { icon: 'pills.fill', titleKey: 'health.tabs.medications' },
|
||||
fasting: { icon: 'timer', titleKey: 'health.tabs.fasting' },
|
||||
challenges: { icon: 'trophy.fill', titleKey: 'health.tabs.challenges' },
|
||||
personal: { icon: 'person.fill', titleKey: 'health.tabs.personal' },
|
||||
};
|
||||
|
||||
export default function TabLayout() {
|
||||
|
||||
@@ -260,25 +260,6 @@ export default function PersonalScreen() {
|
||||
}
|
||||
};
|
||||
|
||||
// 数据格式化函数
|
||||
const formatHeight = () => {
|
||||
if (userProfile.height == null) return '--';
|
||||
return `${parseFloat(userProfile.height).toFixed(1)}cm`;
|
||||
};
|
||||
|
||||
const formatWeight = () => {
|
||||
if (userProfile.weight == null) return '--';
|
||||
return `${parseFloat(userProfile.weight).toFixed(1)}kg`;
|
||||
};
|
||||
|
||||
const formatAge = () => {
|
||||
if (!userProfile.birthDate) return '--';
|
||||
const birthDate = new Date(userProfile.birthDate);
|
||||
const today = new Date();
|
||||
const age = today.getFullYear() - birthDate.getFullYear();
|
||||
return `${age}${t('personal.stats.ageSuffix')}`;
|
||||
};
|
||||
|
||||
// 显示名称
|
||||
const displayName = (userProfile.name?.trim()) ? userProfile.name : DEFAULT_MEMBER_NAME;
|
||||
const profileActionLabel = isLoggedIn ? t('personal.edit') : t('personal.login');
|
||||
@@ -454,27 +435,33 @@ export default function PersonalScreen() {
|
||||
);
|
||||
};
|
||||
|
||||
// 数据统计部分
|
||||
const StatsSection = () => (
|
||||
// 健康档案入口组件
|
||||
const HealthProfileEntry = () => (
|
||||
<View style={styles.sectionContainer}>
|
||||
<View style={[styles.cardContainer, {
|
||||
backgroundColor: 'transparent'
|
||||
}]}>
|
||||
<View style={styles.statsContainer}>
|
||||
<View style={styles.statItem}>
|
||||
<Text style={styles.statValue}>{formatHeight()}</Text>
|
||||
<Text style={styles.statLabel}>{t('personal.stats.height')}</Text>
|
||||
<TouchableOpacity
|
||||
style={styles.healthProfileCard}
|
||||
activeOpacity={0.9}
|
||||
onPress={() => router.push(ROUTES.HEALTH_PROFILE)}
|
||||
>
|
||||
<LinearGradient
|
||||
colors={['#FFFFFF', '#F0F4FF']}
|
||||
start={{ x: 0, y: 0 }}
|
||||
end={{ x: 1, y: 1 }}
|
||||
style={styles.healthProfileGradient}
|
||||
>
|
||||
<View style={styles.healthProfileContent}>
|
||||
<View style={styles.healthProfileLeft}>
|
||||
<View style={styles.healthProfileTitleRow}>
|
||||
<Text style={styles.healthProfileTitle}>{t('personal.healthProfile.title') || '健康档案'}</Text>
|
||||
</View>
|
||||
<Text style={styles.healthProfileSubtitle}>{t('personal.healthProfile.subtitle') || '管理您的个人健康数据与家庭档案'}</Text>
|
||||
</View>
|
||||
<View style={styles.healthProfileRight}>
|
||||
<Ionicons name="chevron-forward" size={20} color="#9CA3AF" />
|
||||
</View>
|
||||
</View>
|
||||
<View style={styles.statItem}>
|
||||
<Text style={styles.statValue}>{formatWeight()}</Text>
|
||||
<Text style={styles.statLabel}>{t('personal.stats.weight')}</Text>
|
||||
</View>
|
||||
<View style={styles.statItem}>
|
||||
<Text style={styles.statValue}>{formatAge()}</Text>
|
||||
<Text style={styles.statLabel}>{t('personal.stats.age')}</Text>
|
||||
</View>
|
||||
</View>
|
||||
</View>
|
||||
</LinearGradient>
|
||||
</TouchableOpacity>
|
||||
</View>
|
||||
);
|
||||
|
||||
@@ -824,7 +811,7 @@ export default function PersonalScreen() {
|
||||
>
|
||||
<UserHeader />
|
||||
{userProfile.isVip ? <VipMembershipCard /> : <MembershipBanner />}
|
||||
<StatsSection />
|
||||
<HealthProfileEntry />
|
||||
<BadgesPreviewSection />
|
||||
<View style={styles.fishRecordContainer}>
|
||||
{/* <Image
|
||||
@@ -1315,4 +1302,60 @@ const styles = StyleSheet.create({
|
||||
color: '#9370DB',
|
||||
fontFamily: 'AliBold',
|
||||
},
|
||||
// 健康档案入口样式
|
||||
healthProfileCard: {
|
||||
borderRadius: 16,
|
||||
overflow: 'hidden',
|
||||
shadowColor: '#000',
|
||||
shadowOffset: { width: 0, height: 2 },
|
||||
shadowOpacity: 0.05,
|
||||
shadowRadius: 8,
|
||||
elevation: 2,
|
||||
backgroundColor: '#FFFFFF',
|
||||
},
|
||||
healthProfileGradient: {
|
||||
padding: 16,
|
||||
},
|
||||
healthProfileContent: {
|
||||
flexDirection: 'row',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'space-between',
|
||||
},
|
||||
healthProfileLeft: {
|
||||
flex: 1,
|
||||
marginRight: 16,
|
||||
},
|
||||
healthProfileTitleRow: {
|
||||
flexDirection: 'row',
|
||||
alignItems: 'center',
|
||||
marginBottom: 6,
|
||||
},
|
||||
healthProfileTitle: {
|
||||
fontSize: 16,
|
||||
fontWeight: 'bold',
|
||||
color: '#1F2937',
|
||||
marginRight: 8,
|
||||
fontFamily: 'AliBold',
|
||||
},
|
||||
healthStatusBadge: {
|
||||
backgroundColor: '#ECFDF5',
|
||||
paddingHorizontal: 8,
|
||||
paddingVertical: 2,
|
||||
borderRadius: 10,
|
||||
borderWidth: 1,
|
||||
borderColor: '#A7F3D0',
|
||||
},
|
||||
healthStatusText: {
|
||||
fontSize: 10,
|
||||
color: '#059669',
|
||||
fontWeight: '600',
|
||||
},
|
||||
healthProfileSubtitle: {
|
||||
fontSize: 12,
|
||||
color: '#6B7280',
|
||||
fontFamily: 'AliRegular',
|
||||
},
|
||||
healthProfileRight: {
|
||||
justifyContent: 'center',
|
||||
},
|
||||
});
|
||||
|
||||
@@ -653,9 +653,6 @@ const styles = StyleSheet.create({
|
||||
shadowRadius: 4,
|
||||
elevation: 3,
|
||||
},
|
||||
hrvTestButton: {
|
||||
backgroundColor: '#8B5CF6',
|
||||
},
|
||||
debugButtonText: {
|
||||
fontSize: 12,
|
||||
fontFamily: 'AliRegular',
|
||||
|
||||
Reference in New Issue
Block a user