feat: 更新应用名称及图标,新增HRV数据管理,优化营养记录展示

This commit is contained in:
richarjiang
2025-08-19 19:13:02 +08:00
parent 260546ff46
commit 35cd320ea7
10 changed files with 643 additions and 564 deletions

View File

@@ -172,7 +172,7 @@ export default function CoachScreen() {
const generateWelcomeMessage = useCallback(() => {
const hour = new Date().getHours();
const name = userProfile?.name || '朋友';
const botName = (params?.name || 'Health Bot').toString();
const botName = (params?.name || '海豹助手').toString();
// 时段问候
let timeGreeting = '';
@@ -197,7 +197,7 @@ export default function CoachScreen() {
messages: [
`${timeGreeting}${name}!我是${botName},你的专属健康管理助手。新的一天开始了,让我们一起为你的健康目标努力吧!`,
`${timeGreeting}!早晨是制定健康计划的最佳时机,我是${botName},可以帮你管理营养摄入、运动计划和生活作息。`,
`${timeGreeting}${name}!作为你的Health Bot,我很高兴能陪伴你的健康之旅。无论是饮食营养、健身锻炼还是生活管理,我都能为你提供专业建议。`
`${timeGreeting}${name}!作为你的海豹助手,我很高兴能陪伴你的健康之旅。无论是饮食营养、健身锻炼还是生活管理,我都能为你提供专业建议。`
]
},
{
@@ -213,7 +213,7 @@ export default function CoachScreen() {
messages: [
`${timeGreeting}${name}!午餐时间很关键呢,合理的营养搭配能为下午提供充足能量。我是${botName},可以为你分析饮食营养和热量管理。`,
`${timeGreeting}!忙碌的上午结束了,该关注一下身体需求啦。我是你的健康助手${botName},无论是饮食调整、运动安排还是休息建议,都可以找我。`,
`${timeGreeting}${name}!午间是调整状态的好时机。作为你的Health Bot,我建议关注饮食均衡和适度放松~`
`${timeGreeting}${name}!午间是调整状态的好时机。作为你的海豹助手,我建议关注饮食均衡和适度放松~`
]
},
{
@@ -229,7 +229,7 @@ export default function CoachScreen() {
messages: [
`${timeGreeting}${name}!忙碌了一天,现在是时候关注身心平衡了。我是${botName},可以为你提供放松建议、营养补充和恢复方案。`,
`${timeGreeting}!夜幕降临,这是一天中最适合总结和调整的时刻。我是你的健康伙伴${botName},让我们一起回顾今天的健康表现,规划明天的目标。`,
`${timeGreeting}${name}!晚间时光属于你自己,也是关爱身体的珍贵时间。作为你的Health Bot,我想陪你聊聊如何更好地管理健康生活。`
`${timeGreeting}${name}!晚间时光属于你自己,也是关爱身体的珍贵时间。作为你的海豹助手,我想陪你聊聊如何更好地管理健康生活。`
]
},
{
@@ -250,7 +250,7 @@ export default function CoachScreen() {
},
{
condition: () => userProfile && (!userProfile.pilatesPurposes || userProfile.pilatesPurposes.length === 0),
message: `${timeGreeting}${name}!作为你的Health Bot,我想更好地了解你的健康需求。告诉我你希望在营养摄入、身材管理、健身锻炼或生活管理方面实现什么目标吧~`
message: `${timeGreeting}${name}!作为你的海豹助手,我想更好地了解你的健康需求。告诉我你希望在营养摄入、身材管理、健身锻炼或生活管理方面实现什么目标吧~`
}
];
@@ -1233,7 +1233,7 @@ export default function CoachScreen() {
</TouchableOpacity>
</View>
<Text style={{ color: '#687076', fontSize: 12 }}>Health Bot会根据您的饮食情况给出专业的营养建</Text>
<Text style={{ color: '#687076', fontSize: 12 }}></Text>
</View>
);
}
@@ -1275,7 +1275,7 @@ export default function CoachScreen() {
<Text style={{ color: '#192126', fontWeight: '700' }}></Text>
</TouchableOpacity>
<Text style={{ color: '#687076', fontSize: 12 }}>Health Bot给出更精准的营养分析和建</Text>
<Text style={{ color: '#687076', fontSize: 12 }}></Text>
</View>
);
}

View File

@@ -30,6 +30,7 @@ import { useSafeAreaInsets } from 'react-native-safe-area-context';
export default function ExploreScreen() {
const theme = (useColorScheme() ?? 'light') as 'light' | 'dark';
const colorTokens = Colors[theme];
const stepGoal = useAppSelector((s) => s.user.profile?.dailyStepsGoal) ?? 2000;
const userProfile = useAppSelector((s) => s.user.profile);
@@ -68,6 +69,12 @@ export default function ExploreScreen() {
// HealthKit: 每次页面聚焦都拉取今日数据
const [stepCount, setStepCount] = useState<number | null>(null);
const [activeCalories, setActiveCalories] = useState<number | null>(null);
// 睡眠时长(分钟)
const [sleepDuration, setSleepDuration] = useState<number | null>(null);
// HRV数据
const [hrvValue, setHrvValue] = useState<number>(69);
const [hrvStatus, setHrvStatus] = useState<'放松' | '正常' | '紧张'>('正常');
const [isLoading, setIsLoading] = useState(false);
// 用于触发动画重置的 token当日期或数据变化时更新
const [animToken, setAnimToken] = useState(0);
@@ -108,6 +115,21 @@ export default function ExploreScreen() {
if (latestRequestKeyRef.current === requestKey) {
setStepCount(data.steps);
setActiveCalories(Math.round(data.activeEnergyBurned));
setSleepDuration(data.sleepDuration);
// 模拟HRV数据实际应用中应从HealthKit获取
const simulatedHrv = Math.floor(Math.random() * 80) + 30; // 30-110ms范围
setHrvValue(simulatedHrv);
// 根据HRV值判断状态
if (simulatedHrv >= 70) {
setHrvStatus('放松');
} else if (simulatedHrv >= 40) {
setHrvStatus('正常');
} else {
setHrvStatus('紧张');
}
setAnimToken((t) => t + 1);
} else {
console.log('忽略过期健康数据请求结果key=', requestKey, '最新key=', latestRequestKeyRef.current);
@@ -187,6 +209,61 @@ export default function ExploreScreen() {
<Text style={styles.sectionTitle}></Text>
<WeightHistoryCard />
{/* HRV压力监测卡片 */}
<View style={[styles.hrvCard, { backgroundColor: '#F0F7FF' }]}>
<View style={styles.hrvHeader}>
<View style={styles.hrvIconContainer}>
<Ionicons name="heart" size={24} color="#3B82F6" />
</View>
<Text style={styles.hrvTitle}></Text>
</View>
<View style={styles.hrvContent}>
<View style={styles.hrvValueContainer}>
<Text style={styles.hrvValue}>{hrvValue}</Text>
<Text style={styles.hrvUnit}></Text>
</View>
<View style={[styles.hrvStatus,
hrvStatus === '放松' ? { backgroundColor: '#DCFCE7' } :
hrvStatus === '正常' ? { backgroundColor: '#FEF3C7' } :
{ backgroundColor: '#FEE2E2' }
]}>
<Text style={[styles.hrvStatusText,
hrvStatus === '放松' ? { color: '#166534' } :
hrvStatus === '正常' ? { color: '#92400E' } :
{ color: '#991B1B' }
]}>{hrvStatus}</Text>
<Text style={styles.hrvEmoji}>
{hrvStatus === '放松' ? '😌' :
hrvStatus === '正常' ? '😊' :
'😰'}
</Text>
</View>
</View>
<View style={styles.hrvSliderContainer}>
<View style={styles.hrvSliderTrack}>
<View style={[styles.hrvSliderProgress, {
width: `${Math.min(100, Math.max(0, (hrvValue / 150) * 100))}%`,
backgroundColor: hrvStatus === '放松' ? '#10B981' :
hrvStatus === '正常' ? '#F59E0B' : '#EF4444'
}]} />
</View>
<View style={styles.hrvLabels}>
<Text style={styles.hrvLabel}></Text>
<Text style={styles.hrvLabel}></Text>
<Text style={styles.hrvLabel}></Text>
</View>
</View>
</View>
{/* 查看更多 */}
<View style={styles.viewMoreContainer}>
<Text style={styles.viewMoreText}></Text>
<Ionicons name="chevron-forward" size={16} color="#192126" style={styles.viewMoreIcon} />
</View>
{/* 标题与日期选择 */}
<Text style={styles.monthTitle}>{monthTitle}</Text>
<ScrollView
@@ -549,4 +626,114 @@ const styles = StyleSheet.create({
padding: 4,
marginLeft: 8,
},
viewMoreContainer: {
flexDirection: 'row',
alignItems: 'center',
justifyContent: 'center',
marginBottom: 16,
},
viewMoreText: {
fontSize: 14,
color: '#192126',
},
viewMoreIcon: {
fontSize: 16,
color: '#192126',
marginLeft: 4,
},
hrvCard: {
backgroundColor: '#F0F7FF',
borderRadius: 22,
padding: 20,
marginBottom: 16,
shadowColor: '#000',
shadowOffset: {
width: 0,
height: 2,
},
shadowOpacity: 0.1,
shadowRadius: 8,
elevation: 5,
},
hrvHeader: {
flexDirection: 'row',
alignItems: 'center',
marginBottom: 16,
},
hrvIconContainer: {
width: 40,
height: 40,
borderRadius: 12,
backgroundColor: '#DBEAFE',
alignItems: 'center',
justifyContent: 'center',
marginRight: 12,
},
hrvTitle: {
fontSize: 18,
fontWeight: '800',
color: '#1E293B',
},
hrvContent: {
flexDirection: 'row',
alignItems: 'center',
justifyContent: 'space-between',
marginBottom: 20,
},
hrvValueContainer: {
flexDirection: 'row',
alignItems: 'baseline',
},
hrvValue: {
fontSize: 36,
fontWeight: '800',
color: '#1E293B',
marginRight: 4,
},
hrvUnit: {
fontSize: 16,
fontWeight: '600',
color: '#64748B',
},
hrvStatus: {
flexDirection: 'row',
alignItems: 'center',
backgroundColor: '#DCFCE7',
paddingHorizontal: 12,
paddingVertical: 6,
borderRadius: 20,
},
hrvStatusText: {
fontSize: 14,
fontWeight: '600',
color: '#166534',
marginRight: 4,
},
hrvEmoji: {
fontSize: 16,
},
hrvSliderContainer: {
marginTop: 8,
},
hrvSliderTrack: {
height: 8,
backgroundColor: '#E2E8F0',
borderRadius: 4,
marginBottom: 8,
overflow: 'hidden',
},
hrvSliderProgress: {
height: '100%',
backgroundColor: '#3B82F6',
borderRadius: 4,
},
hrvLabels: {
flexDirection: 'row',
justifyContent: 'space-between',
},
hrvLabel: {
fontSize: 12,
fontWeight: '500',
color: '#64748B',
},
});