feat(auth): 预加载用户数据并优化登录状态同步

- 在启动屏预加载用户 token 与资料,避免首页白屏
- 新增 rehydrateUserSync 同步注入 Redux,减少异步等待
- 登录页兼容 ERR_REQUEST_CANCELED 取消场景
- 各页面统一依赖 isLoggedIn 判断,移除冗余控制台日志
- 步数卡片与详情页改为实时拉取健康数据,不再缓存至 Redux
- 后台任务注册移至顶层,防止重复定义
- 体重记录、HeaderBar 等 UI 细节样式微调
This commit is contained in:
richarjiang
2025-09-15 09:56:42 +08:00
parent 55d133c470
commit 91df01bd79
18 changed files with 967 additions and 1018 deletions

View File

@@ -1,4 +1,4 @@
import React, { useEffect, useMemo, useRef } from 'react';
import React, { useEffect, useMemo, useRef, useState } from 'react';
import {
Animated,
StyleSheet,
@@ -8,26 +8,52 @@ import {
ViewStyle
} from 'react-native';
import { HourlyStepData } from '@/utils/health';
import { fetchHourlyStepSamples, fetchStepCount, HourlyStepData } from '@/utils/health';
import { logger } from '@/utils/logger';
import { useRouter } from 'expo-router';
import { AnimatedNumber } from './AnimatedNumber';
import dayjs from 'dayjs';
// 使用原生View来替代SVG避免导入问题
// import Svg, { Rect } from 'react-native-svg';
interface StepsCardProps {
stepCount: number | null;
curDate: Date
stepGoal: number;
hourlySteps: HourlyStepData[];
style?: ViewStyle;
onPress?: () => void; // 新增点击事件回调
}
const StepsCard: React.FC<StepsCardProps> = ({
stepCount,
stepGoal,
hourlySteps,
curDate,
style,
onPress
}) => {
const router = useRouter();
const [stepCount, setStepCount] = useState(0)
const [hourlySteps, setHourSteps] = useState<HourlyStepData[]>([])
const getStepData = async (date: Date) => {
try {
logger.info('获取步数数据...');
const [steps, hourly] = await Promise.all([
fetchStepCount(date),
fetchHourlyStepSamples(date)
])
setStepCount(steps)
setHourSteps(hourly)
} catch (error) {
logger.error('获取步数数据失败:', error);
}
}
useEffect(() => {
if (curDate) {
getStepData(curDate);
}
}, [curDate]);
// 为每个柱体创建独立的动画值
const animatedValues = useRef(
Array.from({ length: 24 }, () => new Animated.Value(0))
@@ -56,7 +82,7 @@ const StepsCard: React.FC<StepsCardProps> = ({
useEffect(() => {
// 检查是否有实际数据(不只是空数组)
const hasData = chartData && chartData.length > 0 && chartData.some(data => data.steps > 0);
if (hasData) {
// 重置所有动画值
animatedValues.forEach(animValue => animValue.setValue(0));
@@ -154,24 +180,19 @@ const StepsCard: React.FC<StepsCardProps> = ({
</>
);
// 如果有点击事件包装在TouchableOpacity中
if (onPress) {
return (
<TouchableOpacity
style={[styles.container, style]}
onPress={onPress}
activeOpacity={0.8}
>
<CardContent />
</TouchableOpacity>
);
}
// 否则使用普通View
return (
<View style={[styles.container, style]}>
<TouchableOpacity
style={[styles.container, style]}
onPress={() => {
// 传递当前日期参数到详情页
const dateParam = dayjs(curDate).format('YYYY-MM-DD');
router.push(`/steps/detail?date=${dateParam}`);
}}
activeOpacity={0.8}
>
<CardContent />
</View>
</TouchableOpacity>
);
};