Files
digital-pilates/components/statistic/SleepCard.tsx
richarjiang ccfccca7bc feat(health): 完善HealthKit权限管理和数据获取系统
- 重构权限管理,新增SimpleEventEmitter实现状态监听
- 实现完整的健身圆环数据获取(活动热量、锻炼时间、站立小时)
- 优化组件状态管理,支持实时数据刷新和权限状态响应
- 新增useHealthPermissions Hook,简化权限状态管理
- 完善iOS原生代码,支持按小时统计健身数据
- 优化应用启动时权限初始化流程,避免启动弹窗

BREAKING CHANGE: FitnessRingsCard组件API变更,移除手动传参改为自动获取数据
2025-09-19 14:16:11 +08:00

91 lines
2.3 KiB
TypeScript

import { fetchCompleteSleepData, formatSleepTime } from '@/utils/sleepHealthKit';
import dayjs from 'dayjs';
import { Image } from 'expo-image';
import { router } from 'expo-router';
import React, { useEffect, useState } from 'react';
import { StyleSheet, Text, TouchableOpacity, View } from 'react-native';
interface SleepCardProps {
selectedDate?: Date;
style?: object;
}
const SleepCard: React.FC<SleepCardProps> = ({
selectedDate,
style,
}) => {
const [sleepDuration, setSleepDuration] = useState<number | null>(null);
const [loading, setLoading] = useState(false);
// 获取睡眠数据
useEffect(() => {
const loadSleepData = async () => {
if (!selectedDate) return;
try {
setLoading(true);
const data = await fetchCompleteSleepData(selectedDate);
setSleepDuration(data?.totalSleepTime || null);
} catch (error) {
console.error('SleepCard: 获取睡眠数据失败:', error);
setSleepDuration(null);
} finally {
setLoading(false);
}
};
loadSleepData();
}, [selectedDate]);
const CardContent = (
<View style={[styles.container, style]}>
<View style={styles.cardHeaderRow}>
<Image
source={require('@/assets/images/icons/icon-sleep.png')}
style={styles.titleIcon}
/>
<Text style={styles.cardTitle}></Text>
</View>
<Text style={styles.sleepValue}>
{loading ? '加载中...' : (sleepDuration != null ? formatSleepTime(sleepDuration) : '--')}
</Text>
</View>
);
return (
<TouchableOpacity onPress={() => router.push(`/sleep-detail?date=${dayjs(selectedDate).format('YYYY-MM-DD')}`)} activeOpacity={0.7}>
{CardContent}
</TouchableOpacity>
);
};
const styles = StyleSheet.create({
container: {
// Container styles will be inherited from parent (FloatingCard)
},
cardHeaderRow: {
flexDirection: 'row',
alignItems: 'center',
justifyContent: 'flex-start',
},
titleIcon: {
width: 16,
height: 16,
marginRight: 6,
resizeMode: 'contain',
},
cardTitle: {
fontSize: 14,
color: '#192126',
fontWeight: '600',
},
sleepValue: {
fontSize: 16,
color: '#1E40AF',
fontWeight: '700',
marginTop: 8,
},
});
export default SleepCard;