feat: 优化健康数据相关组件及功能

- 在 CoachScreen 中调整键盘高度计算,移除不必要的 insets.bottom
- 更新 Statistics 组件,移除未使用的健康数据相关函数,简化代码
- 修改多个统计卡片,移除不必要的图标属性,提升组件简洁性
- 优化 HealthDataCard 和其他统计卡片的样式,提升视觉一致性
- 更新健康数据获取逻辑,确保数据处理更为准确
- 移除 MoodCard 中的多余元素,简化心情记录展示
- 调整 StressMeter 和其他组件的样式,提升用户体验
This commit is contained in:
richarjiang
2025-08-25 12:44:40 +08:00
parent ee84a801fb
commit be0a8e7393
10 changed files with 83 additions and 197 deletions

View File

@@ -1,5 +1,4 @@
import { AnimatedNumber } from '@/components/AnimatedNumber';
import { LinearGradient } from 'expo-linear-gradient';
import React from 'react';
import { StyleSheet, Text, View } from 'react-native';
@@ -32,17 +31,6 @@ export function BasalMetabolismCard({ value, resetToken, style }: BasalMetabolis
return (
<View style={[styles.container, style]}>
{/* 渐变背景 */}
<LinearGradient
colors={['#F0F9FF', '#E0F2FE']}
style={styles.gradientBackground}
start={{ x: 0, y: 0 }}
end={{ x: 1, y: 1 }}
/>
{/* 装饰性圆圈 */}
<View style={styles.decorativeCircle1} />
<View style={styles.decorativeCircle2} />
{/* 头部区域 */}
<View style={styles.header}>
@@ -88,34 +76,7 @@ const styles = StyleSheet.create({
position: 'relative',
overflow: 'hidden',
},
gradientBackground: {
position: 'absolute',
left: 0,
right: 0,
top: 0,
bottom: 0,
opacity: 0.6,
},
decorativeCircle1: {
position: 'absolute',
top: -20,
right: -20,
width: 60,
height: 60,
borderRadius: 30,
backgroundColor: '#0EA5E9',
opacity: 0.1,
},
decorativeCircle2: {
position: 'absolute',
bottom: -15,
left: -15,
width: 40,
height: 40,
borderRadius: 20,
backgroundColor: '#0EA5E9',
opacity: 0.05,
},
header: {
flexDirection: 'row',
alignItems: 'center',

View File

@@ -67,20 +67,39 @@ export const DateSelector: React.FC<DateSelectorProps> = ({
const maxScrollOffset = Math.max(0, (days.length * itemWidth) - scrollWidth);
const finalOffset = Math.min(centerOffset, maxScrollOffset);
daysScrollRef.current.scrollTo({ x: finalOffset, animated });
if (animated) {
// 使用原生动画API实现更平滑的滚动
requestAnimationFrame(() => {
daysScrollRef.current?.scrollTo({
x: finalOffset,
animated: true
});
});
} else {
// 非动画情况直接跳转
daysScrollRef.current?.scrollTo({
x: finalOffset,
animated: false
});
}
};
// 初始化时滚动到选中项
useEffect(() => {
if (scrollWidth > 0 && autoScrollToSelected) {
scrollToIndex(selectedIndex, false);
scrollToIndex(selectedIndex, true);
}
}, [scrollWidth, selectedIndex, autoScrollToSelected]);
// 当选中索引变化时,滚动到对应位置
useEffect(() => {
if (scrollWidth > 0 && autoScrollToSelected) {
scrollToIndex(selectedIndex, true);
// 添加微小延迟以确保动画效果更明显
const timer = setTimeout(() => {
scrollToIndex(selectedIndex, true);
}, 50);
return () => clearTimeout(timer);
}
}, [selectedIndex, autoScrollToSelected]);
@@ -94,6 +113,11 @@ export const DateSelector: React.FC<DateSelectorProps> = ({
return;
}
// 先滚动到目标位置,再更新状态
if (autoScrollToSelected) {
scrollToIndex(index, true);
}
// 更新内部状态(如果使用外部控制则不更新)
if (externalSelectedIndex === undefined) {
setInternalSelectedIndex(index);

View File

@@ -14,20 +14,8 @@ export function MoodCard({ moodCheckin, onPress, isLoading = false }: MoodCardPr
return (
<TouchableOpacity onPress={onPress} style={styles.moodCardContent} disabled={isLoading}>
<View style={styles.cardHeaderRow}>
<View style={styles.moodIconContainer}>
{moodCheckin ? (
<Text style={styles.moodIcon}>
{moodConfig?.emoji || '😊'}
</Text>
) : (
<Text style={styles.moodIcon}>😊</Text>
)}
</View>
<Text style={styles.cardTitle}></Text>
</View>
<Text style={styles.cardTitle}></Text>
<Text style={styles.moodSubtitle}></Text>
{isLoading ? (
<View style={styles.moodPreview}>
@@ -53,39 +41,18 @@ const styles = StyleSheet.create({
moodCardContent: {
width: '100%',
},
cardHeaderRow: {
flexDirection: 'row',
alignItems: 'center',
marginBottom: 12,
},
moodIconContainer: {
width: 24,
height: 24,
borderRadius: 8,
backgroundColor: '#DCFCE7',
alignItems: 'center',
justifyContent: 'center',
marginRight: 10,
},
moodIcon: {
fontSize: 14,
},
cardTitle: {
fontSize: 14,
fontWeight: '800',
color: '#192126',
},
moodSubtitle: {
fontSize: 12,
color: '#6B7280',
marginTop: 4,
marginBottom: 8,
},
moodPreview: {
flexDirection: 'row',
justifyContent: 'space-between',
alignItems: 'center',
marginTop: 4,
marginTop: 22,
},
moodPreviewText: {
fontSize: 14,
@@ -100,12 +67,12 @@ const styles = StyleSheet.create({
fontSize: 12,
color: '#9CA3AF',
fontStyle: 'italic',
marginTop: 4,
marginTop: 22,
},
moodLoadingText: {
fontSize: 12,
color: '#9CA3AF',
fontStyle: 'italic',
marginTop: 4,
marginTop: 22,
},
});

View File

@@ -68,7 +68,6 @@ export function StressMeter({ value, updateTime, style, hrvValue }: StressMeterP
<View style={styles.leftSection}>
<Text style={styles.title}></Text>
</View>
<Text style={styles.emoji}>{getStatusEmoji()}</Text>
</View>
{/* 数值显示区域 */}
@@ -83,7 +82,7 @@ export function StressMeter({ value, updateTime, style, hrvValue }: StressMeterP
{/* 渐变背景进度条 */}
<View style={[styles.progressBar, { width: '100%' }]}>
<LinearGradient
colors={['#EF4444', '#FCD34D', '#10B981']}
colors={['#EF4444', '#FCD34D', '#10B981']}
start={{ x: 0, y: 0 }}
end={{ x: 1, y: 0 }}
style={styles.gradientBar}
@@ -113,8 +112,6 @@ export function StressMeter({ value, updateTime, style, hrvValue }: StressMeterP
const styles = StyleSheet.create({
container: {
backgroundColor: '#FFFFFF',
padding: 2,
shadowColor: '#000',
shadowOffset: {
width: 0,
@@ -147,19 +144,16 @@ const styles = StyleSheet.create({
},
title: {
fontSize: 14,
fontWeight: '700',
fontWeight: '800',
color: '#192126',
},
emoji: {
fontSize: 16,
},
valueSection: {
flexDirection: 'row',
alignItems: 'baseline',
marginBottom: 12,
},
value: {
fontSize: 28,
fontSize: 24,
fontWeight: '800',
color: '#192126',
lineHeight: 32,
@@ -172,7 +166,6 @@ const styles = StyleSheet.create({
},
progressContainer: {
height: 16,
marginBottom: 4,
},
progressTrack: {
height: 8,

View File

@@ -6,7 +6,6 @@ interface HealthDataCardProps {
title: string;
value: string;
unit: string;
icon: React.ReactNode;
style?: object;
}
@@ -14,7 +13,6 @@ const HealthDataCard: React.FC<HealthDataCardProps> = ({
title,
value,
unit,
icon,
style
}) => {
return (
@@ -23,10 +21,6 @@ const HealthDataCard: React.FC<HealthDataCardProps> = ({
exiting={FadeOut.duration(300)}
style={[styles.card, style]}
>
<View style={styles.iconContainer}>
{icon}
</View>
<View style={styles.content}>
<Text style={styles.title}>{title}</Text>
<View style={styles.valueContainer}>
@@ -65,9 +59,9 @@ const styles = StyleSheet.create({
},
title: {
fontSize: 14,
color: '#666',
color: '#192126',
marginBottom: 4,
fontWeight: '600',
fontWeight: '800',
},
valueContainer: {
flexDirection: 'row',

View File

@@ -23,7 +23,6 @@ const HeartRateCard: React.FC<HeartRateCardProps> = ({
title="心率"
value={heartRate !== null && heartRate !== undefined ? Math.round(heartRate).toString() : '--'}
unit="bpm"
icon={heartIcon}
style={style}
/>
);

View File

@@ -23,7 +23,6 @@ const OxygenSaturationCard: React.FC<OxygenSaturationCardProps> = ({
title="血氧饱和度"
value={oxygenSaturation !== null && oxygenSaturation !== undefined ? oxygenSaturation.toFixed(1) : '--'}
unit="%"
icon={oxygenIcon}
style={style}
/>
);