feat(hrv): 添加心率变异性监控和压力评估功能

- 新增 HRV 监听服务,实时监控心率变异性数据
- 实现 HRV 到压力指数的转换算法和压力等级评估
- 添加智能通知服务,在压力偏高时推送健康建议
- 优化日志系统,修复日志丢失问题并增强刷新机制
- 改进个人页面下拉刷新,支持并行数据加载
- 优化勋章数据缓存策略,减少不必要的网络请求
- 重构应用初始化流程,优化权限服务和健康监听服务的启动顺序
- 移除冗余日志输出,提升应用性能
This commit is contained in:
richarjiang
2025-11-18 14:08:20 +08:00
parent 3f21f521ea
commit 21e57634e0
15 changed files with 791 additions and 288 deletions

View File

@@ -22,7 +22,7 @@ import { LinearGradient } from 'expo-linear-gradient';
import { useRouter } from 'expo-router';
import React, { useCallback, useEffect, useMemo, useRef, useState } from 'react';
import { useTranslation } from 'react-i18next';
import { Linking, Modal, ScrollView, StatusBar, StyleSheet, Switch, Text, TouchableOpacity, TouchableWithoutFeedback, View } from 'react-native';
import { Linking, Modal, RefreshControl, ScrollView, StatusBar, StyleSheet, Switch, Text, TouchableOpacity, TouchableWithoutFeedback, View } from 'react-native';
import { useSafeAreaInsets } from 'react-native-safe-area-context';
import { AppLanguage, changeAppLanguage, getNormalizedLanguage } from '@/i18n';
@@ -62,6 +62,7 @@ export default function PersonalScreen() {
const isLgAvaliable = isLiquidGlassAvailable();
const [languageModalVisible, setLanguageModalVisible] = useState(false);
const [isSwitchingLanguage, setIsSwitchingLanguage] = useState(false);
const [refreshing, setRefreshing] = useState(false);
const languageOptions = useMemo<LanguageOption[]>(() => ([
{
@@ -165,18 +166,38 @@ export default function PersonalScreen() {
console.log('badgePreview', badgePreview);
// 页面聚焦时获取最新用户信息
// 首次加载时获取用户信息和数据
useEffect(() => {
dispatch(fetchMyProfile());
dispatch(fetchActivityHistory());
dispatch(fetchAvailableBadges());
}, [dispatch]);
// 页面聚焦时智能刷新(依赖 Redux 的缓存策略)
useFocusEffect(
React.useCallback(() => {
dispatch(fetchMyProfile());
dispatch(fetchActivityHistory());
useCallback(() => {
// 徽章数据由 Redux 的缓存策略控制,只有过期才会重新请求
dispatch(fetchAvailableBadges());
// 不再需要在这里加载推送偏好设置,因为已移到通知设置页面
// 加载开发者模式状态
loadDeveloperModeState();
}, [dispatch])
);
// 手动刷新处理
const onRefresh = useCallback(async () => {
setRefreshing(true);
try {
// 并行刷新所有数据
await Promise.all([
dispatch(fetchMyProfile()).unwrap(),
dispatch(fetchActivityHistory()).unwrap(),
dispatch(fetchAvailableBadges()).unwrap(),
]);
} catch (error) {
log.warn('刷新数据失败', error);
} finally {
setRefreshing(false);
}
}, [dispatch]);
// 移除 loadNotificationPreference 函数,因为已移到通知设置页面
// 加载开发者模式状态
@@ -695,6 +716,15 @@ export default function PersonalScreen() {
paddingHorizontal: 16,
}}
showsVerticalScrollIndicator={false}
refreshControl={
<RefreshControl
refreshing={refreshing}
onRefresh={onRefresh}
tintColor="#9370DB"
colors={['#9370DB']}
progressViewOffset={insets.top}
/>
}
>
<UserHeader />
{userProfile.isVip ? <VipMembershipCard /> : <MembershipBanner />}