- 将教练页面中的“Bot”名称更改为“Seal”,提升品牌一致性 - 在布局文件中调整标签标题和图标,确保与新名称一致 - 新增使用次数显示功能,优化用户对使用情况的了解 - 更新日期选择器样式,增强未来日期的禁用效果 - 优化压力分析模态框的颜色和文本,提升可读性
267 lines
7.1 KiB
TypeScript
267 lines
7.1 KiB
TypeScript
import { Colors } from '@/constants/Colors';
|
||
import { useColorScheme } from '@/hooks/useColorScheme';
|
||
import { LinearGradient } from 'expo-linear-gradient';
|
||
import React from 'react';
|
||
import {
|
||
Modal,
|
||
ScrollView,
|
||
StyleSheet,
|
||
Text,
|
||
TouchableOpacity,
|
||
View
|
||
} from 'react-native';
|
||
|
||
interface StressAnalysisModalProps {
|
||
visible: boolean;
|
||
onClose: () => void;
|
||
hrvValue: number;
|
||
updateTime: Date;
|
||
}
|
||
|
||
export function StressAnalysisModal({ visible, onClose, hrvValue, updateTime }: StressAnalysisModalProps) {
|
||
const colorScheme = useColorScheme();
|
||
const colors = Colors[colorScheme ?? 'light'];
|
||
|
||
// 模拟30天HRV数据
|
||
const hrvData = {
|
||
goodEvents: { percentage: 26, count: 53, range: '>80毫秒' },
|
||
energetic: { percentage: 47, count: 97, range: '43-80毫秒' },
|
||
stressed: { percentage: 27, count: 56, range: '<43毫秒' },
|
||
};
|
||
|
||
|
||
|
||
return (
|
||
<Modal
|
||
visible={visible}
|
||
animationType="slide"
|
||
presentationStyle="pageSheet"
|
||
onRequestClose={onClose}
|
||
>
|
||
<LinearGradient
|
||
colors={[colors.backgroundGradientStart, colors.backgroundGradientEnd]}
|
||
style={styles.modalContainer}
|
||
start={{ x: 0, y: 0 }}
|
||
end={{ x: 0, y: 1 }}
|
||
>
|
||
<ScrollView style={styles.content} showsVerticalScrollIndicator={false}>
|
||
{/* 标题 */}
|
||
<Text style={styles.title}>压力情况分析</Text>
|
||
|
||
|
||
{/* 最近30天HRV情况 */}
|
||
<Text style={styles.sectionTitle}>最近30天HRV情况</Text>
|
||
|
||
{/* 彩色横条图 */}
|
||
<View style={styles.chartContainer}>
|
||
<View style={styles.colorBar}>
|
||
<LinearGradient
|
||
colors={['#F59E0B', '#3B82F6', '#10B981']}
|
||
start={{ x: 0, y: 0 }}
|
||
end={{ x: 1, y: 0 }}
|
||
style={styles.gradientBar}
|
||
/>
|
||
</View>
|
||
<View style={styles.legend}>
|
||
<View style={styles.legendItem}>
|
||
<View style={[styles.legendDot, { backgroundColor: '#F59E0B' }]} />
|
||
<Text style={styles.legendText}>鸭梨山大</Text>
|
||
</View>
|
||
<View style={styles.legendItem}>
|
||
<View style={[styles.legendDot, { backgroundColor: '#3B82F6' }]} />
|
||
<Text style={styles.legendText}>活力满满</Text>
|
||
</View>
|
||
<View style={styles.legendItem}>
|
||
<View style={[styles.legendDot, { backgroundColor: '#10B981' }]} />
|
||
<Text style={styles.legendText}>好事发生</Text>
|
||
</View>
|
||
</View>
|
||
</View>
|
||
|
||
{/* 数据统计卡片 */}
|
||
<View style={styles.statsCard}>
|
||
{/* 好事发生 & 活力满满 */}
|
||
<View style={styles.statsRow}>
|
||
<View style={styles.statItem}>
|
||
<Text style={[styles.statTitle, { color: '#10B981' }]}>好事发生</Text>
|
||
<Text style={styles.statPercentage}>{hrvData.goodEvents.percentage}%</Text>
|
||
<View style={styles.statDetails}>
|
||
<Text style={styles.statRange}>❤️ {hrvData.goodEvents.range}</Text>
|
||
</View>
|
||
<Text style={styles.statCount}>{hrvData.goodEvents.count}次</Text>
|
||
</View>
|
||
|
||
<View style={styles.statItem}>
|
||
<Text style={[styles.statTitle, { color: '#3B82F6' }]}>活力满满</Text>
|
||
<Text style={styles.statPercentage}>{hrvData.energetic.percentage}%</Text>
|
||
<View style={styles.statDetails}>
|
||
<Text style={styles.statRange}>❤️ {hrvData.energetic.range}</Text>
|
||
</View>
|
||
<Text style={styles.statCount}>{hrvData.energetic.count}次</Text>
|
||
</View>
|
||
</View>
|
||
|
||
{/* 鸭梨山大 */}
|
||
<View style={styles.statItem}>
|
||
<Text style={[styles.statTitle, { color: '#F59E0B' }]}>鸭梨山大</Text>
|
||
<Text style={styles.statPercentage}>{hrvData.stressed.percentage}%</Text>
|
||
<View style={styles.statDetails}>
|
||
<Text style={styles.statRange}>❤️ {hrvData.stressed.range}</Text>
|
||
</View>
|
||
<Text style={styles.statCount}>{hrvData.stressed.count}次</Text>
|
||
</View>
|
||
</View>
|
||
</ScrollView>
|
||
|
||
{/* 底部继续按钮 */}
|
||
<View style={styles.bottomContainer}>
|
||
<TouchableOpacity style={styles.continueButton} onPress={onClose}>
|
||
<View style={styles.buttonBackground}>
|
||
<Text style={styles.buttonText}>继续</Text>
|
||
</View>
|
||
</TouchableOpacity>
|
||
<View style={styles.homeIndicator} />
|
||
</View>
|
||
</LinearGradient>
|
||
</Modal>
|
||
);
|
||
}
|
||
|
||
const styles = StyleSheet.create({
|
||
modalContainer: {
|
||
flex: 1,
|
||
},
|
||
content: {
|
||
flex: 1,
|
||
paddingHorizontal: 20,
|
||
},
|
||
title: {
|
||
fontSize: 24,
|
||
fontWeight: '800',
|
||
color: '#111827',
|
||
textAlign: 'center',
|
||
marginTop: 20,
|
||
marginBottom: 32,
|
||
},
|
||
|
||
sectionTitle: {
|
||
fontSize: 22,
|
||
fontWeight: '800',
|
||
color: '#111827',
|
||
marginBottom: 20,
|
||
},
|
||
chartContainer: {
|
||
marginBottom: 32,
|
||
},
|
||
colorBar: {
|
||
height: 16,
|
||
borderRadius: 8,
|
||
overflow: 'hidden',
|
||
marginBottom: 16,
|
||
},
|
||
gradientBar: {
|
||
flex: 1,
|
||
},
|
||
legend: {
|
||
flexDirection: 'row',
|
||
justifyContent: 'space-around',
|
||
},
|
||
legendItem: {
|
||
flexDirection: 'row',
|
||
alignItems: 'center',
|
||
},
|
||
legendDot: {
|
||
width: 12,
|
||
height: 12,
|
||
borderRadius: 6,
|
||
marginRight: 6,
|
||
},
|
||
legendText: {
|
||
fontSize: 14,
|
||
fontWeight: '600',
|
||
color: '#374151',
|
||
},
|
||
statsCard: {
|
||
backgroundColor: '#FFFFFF',
|
||
borderRadius: 16,
|
||
padding: 20,
|
||
marginBottom: 32,
|
||
shadowColor: '#000',
|
||
shadowOffset: {
|
||
width: 0,
|
||
height: 2,
|
||
},
|
||
shadowOpacity: 0.05,
|
||
shadowRadius: 8,
|
||
elevation: 2,
|
||
},
|
||
statsRow: {
|
||
flexDirection: 'row',
|
||
gap: 20,
|
||
marginBottom: 24,
|
||
},
|
||
statItem: {
|
||
flex: 1,
|
||
},
|
||
statTitle: {
|
||
fontSize: 16,
|
||
fontWeight: '700',
|
||
marginBottom: 8,
|
||
},
|
||
statPercentage: {
|
||
fontSize: 36,
|
||
fontWeight: '800',
|
||
color: '#111827',
|
||
marginBottom: 4,
|
||
},
|
||
statDetails: {
|
||
marginBottom: 4,
|
||
},
|
||
statRange: {
|
||
fontSize: 14,
|
||
fontWeight: '600',
|
||
color: '#DC2626',
|
||
backgroundColor: '#FEE2E2',
|
||
paddingHorizontal: 8,
|
||
paddingVertical: 3,
|
||
borderRadius: 10,
|
||
alignSelf: 'flex-start',
|
||
},
|
||
statCount: {
|
||
fontSize: 16,
|
||
fontWeight: '600',
|
||
color: '#6B7280',
|
||
},
|
||
bottomContainer: {
|
||
paddingHorizontal: 20,
|
||
paddingBottom: 34,
|
||
},
|
||
continueButton: {
|
||
borderRadius: 25,
|
||
overflow: 'hidden',
|
||
marginBottom: 8,
|
||
},
|
||
buttonGradient: {
|
||
paddingVertical: 18,
|
||
alignItems: 'center',
|
||
justifyContent: 'center',
|
||
},
|
||
buttonBackground: {
|
||
backgroundColor: Colors.light.accentGreen, // 应用主色调
|
||
paddingVertical: 18,
|
||
alignItems: 'center',
|
||
justifyContent: 'center',
|
||
},
|
||
buttonText: {
|
||
fontSize: 18,
|
||
fontWeight: '700',
|
||
color: '#192126', // 主色调上的文字颜色
|
||
},
|
||
homeIndicator: {
|
||
width: 134,
|
||
height: 5,
|
||
backgroundColor: '#000',
|
||
borderRadius: 3,
|
||
alignSelf: 'center',
|
||
},
|
||
}); |