- 在应用中新增健康咨询页面,展示用户健康数据和建议 - 集成 expo-linear-gradient 以实现页面背景渐变效果 - 更新 package.json 和 package-lock.json,添加 expo-linear-gradient 依赖 - 在首页中添加健康咨询的导航链接 - 修改布局以支持新页面的显示和交互
481 lines
12 KiB
TypeScript
481 lines
12 KiB
TypeScript
import { ThemedText } from '@/components/ThemedText';
|
||
import { ThemedView } from '@/components/ThemedView';
|
||
import { useThemeColor } from '@/hooks/useThemeColor';
|
||
import { Ionicons } from '@expo/vector-icons';
|
||
import { LinearGradient } from 'expo-linear-gradient';
|
||
import { useRouter } from 'expo-router';
|
||
import React, { useEffect, useState } from 'react';
|
||
import {
|
||
Dimensions,
|
||
Pressable,
|
||
SafeAreaView,
|
||
ScrollView,
|
||
StyleSheet,
|
||
Text,
|
||
View
|
||
} from 'react-native';
|
||
|
||
const { width: screenWidth } = Dimensions.get('window');
|
||
|
||
// 健康数据项类型
|
||
interface HealthItem {
|
||
id: string;
|
||
title: string;
|
||
subtitle: string;
|
||
status: 'warning' | 'good' | 'info';
|
||
icon: string;
|
||
recommendation: string;
|
||
value?: string;
|
||
color: string;
|
||
bgColor: string;
|
||
}
|
||
|
||
// 健康数据
|
||
const healthData: HealthItem[] = [
|
||
{
|
||
id: '1',
|
||
title: '运动状态',
|
||
subtitle: '本周运动不足',
|
||
status: 'warning',
|
||
icon: '🏃♀️',
|
||
recommendation: '建议每天进行30分钟普拉提训练',
|
||
value: '2天/周',
|
||
color: '#FF6B6B',
|
||
bgColor: '#FFE5E5',
|
||
},
|
||
{
|
||
id: '2',
|
||
title: '体态评估',
|
||
subtitle: '需要进行评估',
|
||
status: 'info',
|
||
icon: '🧘♀️',
|
||
recommendation: '进行AI体态评估,了解身体状况',
|
||
color: '#4ECDC4',
|
||
bgColor: '#E5F9F7',
|
||
},
|
||
{
|
||
id: '3',
|
||
title: '核心力量',
|
||
subtitle: '待加强',
|
||
status: 'warning',
|
||
icon: '💪',
|
||
recommendation: '推荐核心训练课程',
|
||
value: '初级',
|
||
color: '#FFB84D',
|
||
bgColor: '#FFF4E5',
|
||
},
|
||
{
|
||
id: '4',
|
||
title: '柔韧性',
|
||
subtitle: '良好',
|
||
status: 'good',
|
||
icon: '🤸♀️',
|
||
recommendation: '保持每日拉伸习惯',
|
||
value: '良好',
|
||
color: '#95E1D3',
|
||
bgColor: '#E5F9F5',
|
||
},
|
||
{
|
||
id: '5',
|
||
title: '平衡能力',
|
||
subtitle: '需要提升',
|
||
status: 'info',
|
||
icon: '⚖️',
|
||
recommendation: '尝试单腿站立训练',
|
||
color: '#A8E6CF',
|
||
bgColor: '#E8F8F0',
|
||
},
|
||
{
|
||
id: '6',
|
||
title: '呼吸质量',
|
||
subtitle: '待改善',
|
||
status: 'warning',
|
||
icon: '🌬️',
|
||
recommendation: '学习普拉提呼吸法',
|
||
color: '#C7CEEA',
|
||
bgColor: '#F0F1F8',
|
||
},
|
||
];
|
||
|
||
export default function HealthConsultationScreen() {
|
||
const router = useRouter();
|
||
const primaryColor = useThemeColor({}, 'primary');
|
||
const backgroundColor = useThemeColor({}, 'background');
|
||
const textColor = useThemeColor({}, 'text');
|
||
const [greeting, setGreeting] = useState('');
|
||
|
||
useEffect(() => {
|
||
const hour = new Date().getHours();
|
||
if (hour < 12) {
|
||
setGreeting('早上好');
|
||
} else if (hour < 18) {
|
||
setGreeting('下午好');
|
||
} else {
|
||
setGreeting('晚上好');
|
||
}
|
||
}, []);
|
||
|
||
const handleHealthItemPress = (item: HealthItem) => {
|
||
// 根据不同的健康项导航到相应页面
|
||
if (item.title === '体态评估') {
|
||
router.push('/ai-posture-assessment');
|
||
} else {
|
||
console.log(`点击了 ${item.title}`);
|
||
// 可以添加更多导航逻辑
|
||
}
|
||
};
|
||
|
||
return (
|
||
<SafeAreaView style={[styles.safeArea, { backgroundColor }]}>
|
||
<ThemedView style={styles.container}>
|
||
<ScrollView showsVerticalScrollIndicator={false}>
|
||
{/* 顶部导航栏 */}
|
||
<View style={styles.header}>
|
||
<Pressable onPress={() => router.back()} style={styles.backButton}>
|
||
<Ionicons name="chevron-back" size={24} color={textColor} />
|
||
</Pressable>
|
||
<ThemedText style={styles.headerTitle}>健康咨询</ThemedText>
|
||
<Pressable style={styles.notificationButton}>
|
||
<Ionicons name="notifications-outline" size={24} color={textColor} />
|
||
</Pressable>
|
||
</View>
|
||
|
||
{/* 教练问候卡片 */}
|
||
<LinearGradient
|
||
colors={[primaryColor, '#A8E063']}
|
||
start={{ x: 0, y: 0 }}
|
||
end={{ x: 1, y: 1 }}
|
||
style={styles.coachCard}
|
||
>
|
||
<View style={styles.coachContent}>
|
||
<View style={styles.coachInfo}>
|
||
<View style={styles.coachAvatar}>
|
||
<Text style={styles.coachAvatarEmoji}>👩⚕️</Text>
|
||
</View>
|
||
<View style={styles.coachTextContainer}>
|
||
<Text style={styles.coachGreeting}>{greeting},</Text>
|
||
<Text style={styles.coachName}>我是您的普拉提教练 Sarah</Text>
|
||
</View>
|
||
</View>
|
||
<Text style={styles.coachQuestion}>今天感觉怎么样?</Text>
|
||
<Text style={styles.coachSubtext}>让我们一起了解您的身体状况</Text>
|
||
</View>
|
||
</LinearGradient>
|
||
|
||
{/* 快速操作按钮 */}
|
||
<View style={styles.quickActions}>
|
||
<Pressable style={[styles.actionButton, { backgroundColor: primaryColor }]}>
|
||
<Ionicons name="body-outline" size={20} color="#192126" />
|
||
<Text style={styles.actionButtonText}>体态检测</Text>
|
||
</Pressable>
|
||
<Pressable style={[styles.actionButton, styles.actionButtonOutline]}>
|
||
<Ionicons name="chatbubble-outline" size={20} color={textColor} />
|
||
<Text style={[styles.actionButtonText, { color: textColor }]}>咨询教练</Text>
|
||
</Pressable>
|
||
<Pressable style={[styles.actionButton, styles.actionButtonOutline]}>
|
||
<Ionicons name="calendar-outline" size={20} color={textColor} />
|
||
<Text style={[styles.actionButtonText, { color: textColor }]}>预约课程</Text>
|
||
</Pressable>
|
||
</View>
|
||
|
||
{/* 健康状况标题 */}
|
||
<View style={styles.sectionHeader}>
|
||
<ThemedText style={styles.sectionTitle}>您的健康状况</ThemedText>
|
||
<View style={[styles.healthBadge, { backgroundColor: primaryColor }]}>
|
||
<Text style={styles.healthBadgeText}>需要关注</Text>
|
||
</View>
|
||
</View>
|
||
|
||
{/* 健康数据网格 */}
|
||
<View style={styles.healthGrid}>
|
||
{healthData.map((item) => (
|
||
<Pressable
|
||
key={item.id}
|
||
style={[styles.healthCard, { backgroundColor: item.bgColor }]}
|
||
onPress={() => handleHealthItemPress(item)}
|
||
>
|
||
<View style={styles.healthCardHeader}>
|
||
<Text style={styles.healthIcon}>{item.icon}</Text>
|
||
{item.value && (
|
||
<Text style={[styles.healthValue, { color: item.color }]}>
|
||
{item.value}
|
||
</Text>
|
||
)}
|
||
</View>
|
||
<Text style={styles.healthTitle}>{item.title}</Text>
|
||
<Text style={styles.healthSubtitle}>{item.subtitle}</Text>
|
||
<View style={styles.healthRecommendation}>
|
||
<Ionicons name="bulb-outline" size={12} color={item.color} />
|
||
<Text style={[styles.recommendationText, { color: item.color }]} numberOfLines={2}>
|
||
{item.recommendation}
|
||
</Text>
|
||
</View>
|
||
<Ionicons
|
||
name="arrow-forward-circle"
|
||
size={20}
|
||
color={item.color}
|
||
style={styles.cardArrow}
|
||
/>
|
||
</Pressable>
|
||
))}
|
||
</View>
|
||
|
||
{/* 今日建议 */}
|
||
<View style={styles.suggestionSection}>
|
||
<ThemedText style={styles.suggestionTitle}>今日建议</ThemedText>
|
||
<View style={[styles.suggestionCard, { backgroundColor: '#F0F8FF' }]}>
|
||
<View style={styles.suggestionIcon}>
|
||
<Text style={{ fontSize: 24 }}>💡</Text>
|
||
</View>
|
||
<View style={styles.suggestionContent}>
|
||
<Text style={styles.suggestionMainText}>
|
||
根据您的身体状况,建议今天进行轻度核心训练
|
||
</Text>
|
||
<Text style={styles.suggestionSubText}>
|
||
配合呼吸练习,效果更佳
|
||
</Text>
|
||
<Pressable style={[styles.startButton, { backgroundColor: primaryColor }]}>
|
||
<Text style={styles.startButtonText}>开始训练</Text>
|
||
<Ionicons name="arrow-forward" size={16} color="#192126" />
|
||
</Pressable>
|
||
</View>
|
||
</View>
|
||
</View>
|
||
|
||
{/* 底部间距 */}
|
||
<View style={styles.bottomSpacing} />
|
||
</ScrollView>
|
||
</ThemedView>
|
||
</SafeAreaView>
|
||
);
|
||
}
|
||
|
||
const styles = StyleSheet.create({
|
||
safeArea: {
|
||
flex: 1,
|
||
},
|
||
container: {
|
||
flex: 1,
|
||
},
|
||
header: {
|
||
flexDirection: 'row',
|
||
alignItems: 'center',
|
||
justifyContent: 'space-between',
|
||
paddingHorizontal: 20,
|
||
paddingVertical: 12,
|
||
},
|
||
backButton: {
|
||
padding: 8,
|
||
},
|
||
headerTitle: {
|
||
fontSize: 18,
|
||
fontWeight: '600',
|
||
},
|
||
notificationButton: {
|
||
padding: 8,
|
||
},
|
||
coachCard: {
|
||
marginHorizontal: 20,
|
||
marginTop: 12,
|
||
borderRadius: 20,
|
||
padding: 24,
|
||
elevation: 5,
|
||
shadowColor: '#000',
|
||
shadowOffset: { width: 0, height: 2 },
|
||
shadowOpacity: 0.1,
|
||
shadowRadius: 8,
|
||
},
|
||
coachContent: {
|
||
gap: 16,
|
||
},
|
||
coachInfo: {
|
||
flexDirection: 'row',
|
||
alignItems: 'center',
|
||
gap: 12,
|
||
},
|
||
coachAvatar: {
|
||
width: 50,
|
||
height: 50,
|
||
borderRadius: 25,
|
||
backgroundColor: '#fff',
|
||
alignItems: 'center',
|
||
justifyContent: 'center',
|
||
},
|
||
coachAvatarEmoji: {
|
||
fontSize: 30,
|
||
},
|
||
coachTextContainer: {
|
||
flex: 1,
|
||
},
|
||
coachGreeting: {
|
||
fontSize: 14,
|
||
color: '#192126',
|
||
opacity: 0.8,
|
||
},
|
||
coachName: {
|
||
fontSize: 16,
|
||
fontWeight: '600',
|
||
color: '#192126',
|
||
},
|
||
coachQuestion: {
|
||
fontSize: 28,
|
||
fontWeight: 'bold',
|
||
color: '#192126',
|
||
marginTop: 8,
|
||
},
|
||
coachSubtext: {
|
||
fontSize: 14,
|
||
color: '#192126',
|
||
opacity: 0.7,
|
||
},
|
||
quickActions: {
|
||
flexDirection: 'row',
|
||
paddingHorizontal: 20,
|
||
marginTop: 20,
|
||
gap: 12,
|
||
},
|
||
actionButton: {
|
||
flex: 1,
|
||
flexDirection: 'row',
|
||
alignItems: 'center',
|
||
justifyContent: 'center',
|
||
paddingVertical: 12,
|
||
borderRadius: 12,
|
||
gap: 6,
|
||
},
|
||
actionButtonOutline: {
|
||
borderWidth: 1,
|
||
borderColor: '#E0E0E0',
|
||
},
|
||
actionButtonText: {
|
||
fontSize: 14,
|
||
fontWeight: '500',
|
||
},
|
||
sectionHeader: {
|
||
flexDirection: 'row',
|
||
alignItems: 'center',
|
||
justifyContent: 'space-between',
|
||
paddingHorizontal: 20,
|
||
marginTop: 32,
|
||
marginBottom: 16,
|
||
},
|
||
sectionTitle: {
|
||
fontSize: 22,
|
||
fontWeight: 'bold',
|
||
},
|
||
healthBadge: {
|
||
paddingHorizontal: 12,
|
||
paddingVertical: 6,
|
||
borderRadius: 12,
|
||
},
|
||
healthBadgeText: {
|
||
fontSize: 12,
|
||
fontWeight: '600',
|
||
color: '#192126',
|
||
},
|
||
healthGrid: {
|
||
flexDirection: 'row',
|
||
flexWrap: 'wrap',
|
||
paddingHorizontal: 16,
|
||
gap: 12,
|
||
},
|
||
healthCard: {
|
||
width: (screenWidth - 44) / 2,
|
||
padding: 16,
|
||
borderRadius: 16,
|
||
position: 'relative',
|
||
},
|
||
healthCardHeader: {
|
||
flexDirection: 'row',
|
||
justifyContent: 'space-between',
|
||
alignItems: 'center',
|
||
marginBottom: 8,
|
||
},
|
||
healthIcon: {
|
||
fontSize: 28,
|
||
},
|
||
healthValue: {
|
||
fontSize: 12,
|
||
fontWeight: '600',
|
||
},
|
||
healthTitle: {
|
||
fontSize: 16,
|
||
fontWeight: '600',
|
||
color: '#192126',
|
||
marginBottom: 4,
|
||
},
|
||
healthSubtitle: {
|
||
fontSize: 13,
|
||
color: '#666',
|
||
marginBottom: 12,
|
||
},
|
||
healthRecommendation: {
|
||
flexDirection: 'row',
|
||
alignItems: 'flex-start',
|
||
gap: 6,
|
||
paddingRight: 20,
|
||
},
|
||
recommendationText: {
|
||
fontSize: 11,
|
||
flex: 1,
|
||
},
|
||
cardArrow: {
|
||
position: 'absolute',
|
||
bottom: 12,
|
||
right: 12,
|
||
},
|
||
suggestionSection: {
|
||
paddingHorizontal: 20,
|
||
marginTop: 32,
|
||
},
|
||
suggestionTitle: {
|
||
fontSize: 22,
|
||
fontWeight: 'bold',
|
||
marginBottom: 16,
|
||
},
|
||
suggestionCard: {
|
||
flexDirection: 'row',
|
||
padding: 20,
|
||
borderRadius: 16,
|
||
gap: 16,
|
||
},
|
||
suggestionIcon: {
|
||
width: 40,
|
||
height: 40,
|
||
borderRadius: 20,
|
||
backgroundColor: '#fff',
|
||
alignItems: 'center',
|
||
justifyContent: 'center',
|
||
},
|
||
suggestionContent: {
|
||
flex: 1,
|
||
gap: 8,
|
||
},
|
||
suggestionMainText: {
|
||
fontSize: 15,
|
||
fontWeight: '500',
|
||
color: '#192126',
|
||
},
|
||
suggestionSubText: {
|
||
fontSize: 13,
|
||
color: '#666',
|
||
},
|
||
startButton: {
|
||
flexDirection: 'row',
|
||
alignItems: 'center',
|
||
alignSelf: 'flex-start',
|
||
paddingHorizontal: 16,
|
||
paddingVertical: 8,
|
||
borderRadius: 20,
|
||
marginTop: 8,
|
||
gap: 6,
|
||
},
|
||
startButtonText: {
|
||
fontSize: 14,
|
||
fontWeight: '600',
|
||
color: '#192126',
|
||
},
|
||
bottomSpacing: {
|
||
height: 100,
|
||
},
|
||
}); |