feat: 新增基础代谢详情页面并优化HRV数据获取逻辑

- 新增基础代谢详情页面,包含图表展示、数据缓存和防抖机制
- 优化HRV数据获取逻辑,支持实时、近期和历史数据的智能获取
- 移除WaterIntakeCard和WaterSettings中的登录验证逻辑
- 更新饮水数据管理hook,直接使用HealthKit数据
- 添加饮水目标存储和获取功能
- 更新依赖包版本
This commit is contained in:
richarjiang
2025-09-25 14:15:42 +08:00
parent 83e534c4a7
commit 79ab354f31
12 changed files with 1563 additions and 702 deletions

View File

@@ -6,7 +6,7 @@ import dayjs from 'dayjs';
import { Image } from 'expo-image';
import { router } from 'expo-router';
import React, { useCallback, useEffect, useMemo, useRef, useState } from 'react';
import { Modal, StyleSheet, Text, TouchableOpacity, View } from 'react-native';
import { StyleSheet, Text, TouchableOpacity, View } from 'react-native';
interface BasalMetabolismCardProps {
selectedDate?: Date;
@@ -16,7 +16,6 @@ interface BasalMetabolismCardProps {
export function BasalMetabolismCard({ selectedDate, style }: BasalMetabolismCardProps) {
const [basalMetabolism, setBasalMetabolism] = useState<number | null>(null);
const [loading, setLoading] = useState(false);
const [modalVisible, setModalVisible] = useState(false);
// 获取用户基本信息
const userProfile = useAppSelector(selectUserProfile);
@@ -154,7 +153,7 @@ export function BasalMetabolismCard({ selectedDate, style }: BasalMetabolismCard
<>
<TouchableOpacity
style={[styles.container, style]}
onPress={() => setModalVisible(true)}
onPress={() => router.push(ROUTES.BASAL_METABOLISM_DETAIL)}
activeOpacity={0.8}
>
{/* 头部区域 */}
@@ -179,86 +178,6 @@ export function BasalMetabolismCard({ selectedDate, style }: BasalMetabolismCard
<Text style={styles.unit}>/</Text>
</View>
</TouchableOpacity>
{/* 基础代谢详情弹窗 */}
<Modal
animationType="fade"
transparent={true}
visible={modalVisible}
onRequestClose={() => setModalVisible(false)}
>
<View style={styles.modalOverlay}>
<View style={styles.modalContent}>
{/* 关闭按钮 */}
<TouchableOpacity
style={styles.closeButton}
onPress={() => setModalVisible(false)}
>
<Text style={styles.closeButtonText}>×</Text>
</TouchableOpacity>
{/* 标题 */}
<Text style={styles.modalTitle}></Text>
{/* 基础代谢定义 */}
<Text style={styles.modalDescription}>
BMR
</Text>
{/* 为什么重要 */}
<Text style={styles.sectionTitle}></Text>
<Text style={styles.sectionContent}>
60-75%
</Text>
{/* 正常范围 */}
<Text style={styles.sectionTitle}></Text>
<Text style={styles.formulaText}>
- BMR = 10 × (kg) + 6.25 × (cm) - 5 × + 5
</Text>
<Text style={styles.formulaText}>
- BMR = 10 × (kg) + 6.25 × (cm) - 5 × - 161
</Text>
{bmrRange ? (
<>
<Text style={styles.rangeText}>{bmrRange.min}-{bmrRange.max}/</Text>
<Text style={styles.rangeNote}>
(15%)
</Text>
<Text style={styles.userInfoText}>
{userProfile.gender === 'male' ? '男性' : '女性'}{userAge}{userProfile.height}cm{userProfile.weight}kg
</Text>
</>
) : (
<>
<Text style={styles.rangeText}></Text>
<TouchableOpacity
style={styles.completeInfoButton}
onPress={() => {
setModalVisible(false);
router.push(ROUTES.PROFILE_EDIT);
}}
>
<Text style={styles.completeInfoButtonText}></Text>
</TouchableOpacity>
</>
)}
{/* 提高代谢率的策略 */}
<Text style={styles.sectionTitle}></Text>
<Text style={styles.strategyText}></Text>
<View style={styles.strategyList}>
<Text style={styles.strategyItem}>1. (2-3)</Text>
<Text style={styles.strategyItem}>2. (HIIT)</Text>
<Text style={styles.strategyItem}>3. (1.6-2.2g)</Text>
<Text style={styles.strategyItem}>4. (7-9/)</Text>
<Text style={styles.strategyItem}>5. (BMR的80%)</Text>
</View>
</View>
</View>
</Modal>
</>
);
}
@@ -352,128 +271,4 @@ const styles = StyleSheet.create({
color: '#64748B',
marginLeft: 6,
},
// Modal styles
modalOverlay: {
flex: 1,
backgroundColor: 'rgba(0, 0, 0, 0.5)',
justifyContent: 'flex-end',
},
modalContent: {
backgroundColor: '#FFFFFF',
borderTopLeftRadius: 20,
borderTopRightRadius: 20,
padding: 24,
maxHeight: '90%',
width: '100%',
shadowColor: '#000',
shadowOffset: {
width: 0,
height: -5,
},
shadowOpacity: 0.25,
shadowRadius: 20,
elevation: 10,
},
closeButton: {
position: 'absolute',
top: 16,
right: 16,
width: 32,
height: 32,
borderRadius: 16,
backgroundColor: '#F1F5F9',
alignItems: 'center',
justifyContent: 'center',
zIndex: 1,
},
closeButtonText: {
fontSize: 20,
color: '#64748B',
fontWeight: '600',
},
modalTitle: {
fontSize: 24,
fontWeight: '700',
color: '#0F172A',
marginBottom: 16,
textAlign: 'center',
},
modalDescription: {
fontSize: 15,
color: '#475569',
lineHeight: 22,
marginBottom: 24,
},
sectionTitle: {
fontSize: 18,
fontWeight: '700',
color: '#0F172A',
marginBottom: 12,
marginTop: 8,
},
sectionContent: {
fontSize: 15,
color: '#475569',
lineHeight: 22,
marginBottom: 20,
},
formulaText: {
fontSize: 14,
color: '#64748B',
fontFamily: 'monospace',
marginBottom: 4,
paddingLeft: 8,
},
rangeText: {
fontSize: 16,
fontWeight: '600',
color: '#059669',
marginTop: 12,
marginBottom: 4,
textAlign: 'center',
},
rangeNote: {
fontSize: 12,
color: '#9CA3AF',
textAlign: 'center',
marginBottom: 20,
},
userInfoText: {
fontSize: 13,
color: '#6B7280',
textAlign: 'center',
marginTop: 8,
marginBottom: 16,
fontStyle: 'italic',
},
strategyText: {
fontSize: 15,
color: '#475569',
marginBottom: 12,
},
strategyList: {
marginBottom: 20,
},
strategyItem: {
fontSize: 14,
color: '#64748B',
lineHeight: 20,
marginBottom: 8,
paddingLeft: 8,
},
completeInfoButton: {
backgroundColor: '#7a5af8',
borderRadius: 12,
paddingVertical: 12,
paddingHorizontal: 24,
marginTop: 16,
alignItems: 'center',
alignSelf: 'center',
},
completeInfoButtonText: {
color: '#FFFFFF',
fontSize: 16,
fontWeight: '600',
},
});