feat: 新增 StressMeter 组件,移除原 HRV 压力监测代码
This commit is contained in:
@@ -3,6 +3,7 @@ import { BMICard } from '@/components/BMICard';
|
|||||||
import { CircularRing } from '@/components/CircularRing';
|
import { CircularRing } from '@/components/CircularRing';
|
||||||
import { NutritionRadarCard } from '@/components/NutritionRadarCard';
|
import { NutritionRadarCard } from '@/components/NutritionRadarCard';
|
||||||
import { ProgressBar } from '@/components/ProgressBar';
|
import { ProgressBar } from '@/components/ProgressBar';
|
||||||
|
import { StressMeter } from '@/components/StressMeter';
|
||||||
import { WeightHistoryCard } from '@/components/WeightHistoryCard';
|
import { WeightHistoryCard } from '@/components/WeightHistoryCard';
|
||||||
import { Colors } from '@/constants/Colors';
|
import { Colors } from '@/constants/Colors';
|
||||||
import { getTabBarBottomPadding } from '@/constants/TabBar';
|
import { getTabBarBottomPadding } from '@/constants/TabBar';
|
||||||
@@ -210,53 +211,7 @@ export default function ExploreScreen() {
|
|||||||
<WeightHistoryCard />
|
<WeightHistoryCard />
|
||||||
|
|
||||||
{/* HRV压力监测卡片 */}
|
{/* HRV压力监测卡片 */}
|
||||||
<View style={[styles.hrvCard, { backgroundColor: '#F0F7FF' }]}>
|
<StressMeter value={hrvValue} status={hrvStatus} />
|
||||||
<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}>
|
<View style={styles.viewMoreContainer}>
|
||||||
@@ -641,99 +596,4 @@ const styles = StyleSheet.create({
|
|||||||
color: '#192126',
|
color: '#192126',
|
||||||
marginLeft: 4,
|
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',
|
|
||||||
},
|
|
||||||
});
|
});
|
||||||
|
|||||||
170
components/StressMeter.tsx
Normal file
170
components/StressMeter.tsx
Normal file
@@ -0,0 +1,170 @@
|
|||||||
|
import { Ionicons } from '@expo/vector-icons';
|
||||||
|
import { LinearGradient } from 'expo-linear-gradient';
|
||||||
|
import React from 'react';
|
||||||
|
import { StyleSheet, Text, View } from 'react-native';
|
||||||
|
|
||||||
|
interface StressMeterProps {
|
||||||
|
value: number;
|
||||||
|
status: '放松' | '正常' | '紧张';
|
||||||
|
}
|
||||||
|
|
||||||
|
export function StressMeter({ value, status }: StressMeterProps) {
|
||||||
|
// 计算进度条位置(0-100%)
|
||||||
|
const progressPercentage = Math.min(100, Math.max(0, (value / 150) * 100));
|
||||||
|
|
||||||
|
// 根据状态获取颜色
|
||||||
|
const getStatusColor = () => {
|
||||||
|
switch (status) {
|
||||||
|
case '放松': return '#10B981';
|
||||||
|
case '正常': return '#F59E0B';
|
||||||
|
case '紧张': return '#EF4444';
|
||||||
|
default: return '#F59E0B';
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// 根据状态获取表情
|
||||||
|
const getStatusEmoji = () => {
|
||||||
|
switch (status) {
|
||||||
|
case '放松': return '😌';
|
||||||
|
case '正常': return '😊';
|
||||||
|
case '紧张': return '😰';
|
||||||
|
default: return '😊';
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<View style={styles.container}>
|
||||||
|
{/* 头部区域 */}
|
||||||
|
<View style={styles.header}>
|
||||||
|
<View style={styles.leftSection}>
|
||||||
|
<View style={styles.iconContainer}>
|
||||||
|
<Ionicons name="heart" size={20} color="#3B82F6" />
|
||||||
|
</View>
|
||||||
|
<Text style={styles.title}>压力</Text>
|
||||||
|
</View>
|
||||||
|
<Text style={styles.emoji}>{getStatusEmoji()}</Text>
|
||||||
|
</View>
|
||||||
|
|
||||||
|
{/* 数值显示区域 */}
|
||||||
|
<View style={styles.valueSection}>
|
||||||
|
<Text style={styles.value}>{value}</Text>
|
||||||
|
<Text style={styles.unit}>毫秒</Text>
|
||||||
|
</View>
|
||||||
|
|
||||||
|
{/* 进度条区域 */}
|
||||||
|
<View style={styles.progressContainer}>
|
||||||
|
<View style={styles.progressTrack}>
|
||||||
|
{/* 渐变背景进度条 */}
|
||||||
|
<View style={[styles.progressBar, { width: `${progressPercentage}%` }]}>
|
||||||
|
<LinearGradient
|
||||||
|
colors={['#F97316', '#FCD34D', '#84CC16', '#10B981']}
|
||||||
|
start={{ x: 0, y: 0 }}
|
||||||
|
end={{ x: 1, y: 0 }}
|
||||||
|
style={styles.gradientBar}
|
||||||
|
/>
|
||||||
|
</View>
|
||||||
|
{/* 白色圆形指示器 */}
|
||||||
|
<View style={[styles.indicator, { left: `${Math.max(0, progressPercentage - 2)}%` }]} />
|
||||||
|
</View>
|
||||||
|
</View>
|
||||||
|
</View>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
const styles = StyleSheet.create({
|
||||||
|
container: {
|
||||||
|
backgroundColor: '#FFFFFF',
|
||||||
|
borderRadius: 20,
|
||||||
|
padding: 16,
|
||||||
|
marginBottom: 12,
|
||||||
|
shadowColor: '#000',
|
||||||
|
shadowOffset: {
|
||||||
|
width: 0,
|
||||||
|
height: 2,
|
||||||
|
},
|
||||||
|
shadowOpacity: 0.08,
|
||||||
|
shadowRadius: 12,
|
||||||
|
elevation: 3,
|
||||||
|
},
|
||||||
|
header: {
|
||||||
|
flexDirection: 'row',
|
||||||
|
alignItems: 'center',
|
||||||
|
justifyContent: 'space-between',
|
||||||
|
marginBottom: 12,
|
||||||
|
},
|
||||||
|
leftSection: {
|
||||||
|
flexDirection: 'row',
|
||||||
|
alignItems: 'center',
|
||||||
|
},
|
||||||
|
iconContainer: {
|
||||||
|
width: 28,
|
||||||
|
height: 28,
|
||||||
|
borderRadius: 8,
|
||||||
|
backgroundColor: '#EBF4FF',
|
||||||
|
alignItems: 'center',
|
||||||
|
justifyContent: 'center',
|
||||||
|
marginRight: 8,
|
||||||
|
},
|
||||||
|
title: {
|
||||||
|
fontSize: 16,
|
||||||
|
fontWeight: '700',
|
||||||
|
color: '#1F2937',
|
||||||
|
},
|
||||||
|
emoji: {
|
||||||
|
fontSize: 24,
|
||||||
|
},
|
||||||
|
valueSection: {
|
||||||
|
flexDirection: 'row',
|
||||||
|
alignItems: 'baseline',
|
||||||
|
marginBottom: 16,
|
||||||
|
},
|
||||||
|
value: {
|
||||||
|
fontSize: 42,
|
||||||
|
fontWeight: '800',
|
||||||
|
color: '#1F2937',
|
||||||
|
lineHeight: 46,
|
||||||
|
},
|
||||||
|
unit: {
|
||||||
|
fontSize: 14,
|
||||||
|
fontWeight: '500',
|
||||||
|
color: '#6B7280',
|
||||||
|
marginLeft: 4,
|
||||||
|
},
|
||||||
|
progressContainer: {
|
||||||
|
height: 20,
|
||||||
|
},
|
||||||
|
progressTrack: {
|
||||||
|
height: 12,
|
||||||
|
backgroundColor: '#F3F4F6',
|
||||||
|
borderRadius: 6,
|
||||||
|
position: 'relative',
|
||||||
|
overflow: 'visible',
|
||||||
|
},
|
||||||
|
progressBar: {
|
||||||
|
height: '100%',
|
||||||
|
borderRadius: 6,
|
||||||
|
overflow: 'hidden',
|
||||||
|
},
|
||||||
|
gradientBar: {
|
||||||
|
height: '100%',
|
||||||
|
borderRadius: 6,
|
||||||
|
},
|
||||||
|
indicator: {
|
||||||
|
position: 'absolute',
|
||||||
|
top: -4,
|
||||||
|
width: 20,
|
||||||
|
height: 20,
|
||||||
|
borderRadius: 10,
|
||||||
|
backgroundColor: '#FFFFFF',
|
||||||
|
shadowColor: '#000',
|
||||||
|
shadowOffset: {
|
||||||
|
width: 0,
|
||||||
|
height: 2,
|
||||||
|
},
|
||||||
|
shadowOpacity: 0.15,
|
||||||
|
shadowRadius: 4,
|
||||||
|
elevation: 4,
|
||||||
|
borderWidth: 2,
|
||||||
|
borderColor: '#E5E7EB',
|
||||||
|
},
|
||||||
|
});
|
||||||
Reference in New Issue
Block a user