为目标页面、营养记录、食物添加等功能添加登录状态检查和引导界面,确保用户在未登录状态下能够获得清晰的登录提示和指引。 - 在目标页面添加精美的未登录引导界面,包含渐变背景和登录按钮 - 为食物记录相关组件添加登录状态检查,未登录时自动跳转登录页面 - 重构血氧饱和度卡片为独立数据获取,移除对外部数据依赖 - 移除个人页面的实验性SwiftUI组件,统一使用原生TouchableOpacity - 清理统计页面和营养记录页面的冗余代码和未使用变量
123 lines
3.1 KiB
TypeScript
123 lines
3.1 KiB
TypeScript
import { createSlice, PayloadAction } from '@reduxjs/toolkit';
|
|
import { AppDispatch, RootState } from './index';
|
|
|
|
// 健康数据类型定义
|
|
export interface FitnessRingsData {
|
|
activeCalories: number;
|
|
activeCaloriesGoal: number;
|
|
exerciseMinutes: number;
|
|
exerciseMinutesGoal: number;
|
|
standHours: number;
|
|
standHoursGoal: number;
|
|
}
|
|
|
|
export interface HealthData {
|
|
activeCalories: number | null;
|
|
basalEnergyBurned: number | null;
|
|
hrv: number | null;
|
|
heartRate: number | null;
|
|
activeEnergyBurned: number;
|
|
activeCaloriesGoal: number;
|
|
exerciseMinutes: number;
|
|
exerciseMinutesGoal: number;
|
|
standHours: number;
|
|
standHoursGoal: number;
|
|
}
|
|
|
|
export interface HealthState {
|
|
// 按日期存储的历史数据
|
|
dataByDate: Record<string, HealthData>;
|
|
|
|
// 加载状态
|
|
loading: boolean;
|
|
error: string | null;
|
|
|
|
// 最后更新时间
|
|
lastUpdateTime: string | null;
|
|
}
|
|
|
|
// 初始状态
|
|
const initialState: HealthState = {
|
|
dataByDate: {},
|
|
loading: false,
|
|
error: null,
|
|
lastUpdateTime: null,
|
|
};
|
|
|
|
const healthSlice = createSlice({
|
|
name: 'health',
|
|
initialState,
|
|
reducers: {
|
|
// 设置加载状态
|
|
setLoading: (state, action: PayloadAction<boolean>) => {
|
|
state.loading = action.payload;
|
|
},
|
|
|
|
// 设置错误信息
|
|
setError: (state, action: PayloadAction<string | null>) => {
|
|
state.error = action.payload;
|
|
},
|
|
|
|
// 设置完整的健康数据
|
|
setHealthData: (state, action: PayloadAction<{
|
|
date: string;
|
|
data: HealthData;
|
|
}>) => {
|
|
const { date, data } = action.payload;
|
|
|
|
// 存储到历史数据
|
|
state.dataByDate[date] = data;
|
|
|
|
state.lastUpdateTime = new Date().toISOString();
|
|
},
|
|
|
|
// 清除特定日期的数据
|
|
clearHealthDataForDate: (state, action: PayloadAction<string>) => {
|
|
const date = action.payload;
|
|
delete state.dataByDate[date];
|
|
|
|
},
|
|
|
|
// 清除所有健康数据
|
|
clearAllHealthData: (state) => {
|
|
state.dataByDate = {};
|
|
state.error = null;
|
|
state.lastUpdateTime = null;
|
|
},
|
|
},
|
|
});
|
|
|
|
// Action creators
|
|
export const {
|
|
setLoading,
|
|
setError,
|
|
setHealthData,
|
|
clearHealthDataForDate,
|
|
clearAllHealthData,
|
|
} = healthSlice.actions;
|
|
|
|
// Thunk action to fetch and set health data for a specific date
|
|
export const fetchHealthDataForDate = (date: Date) => {
|
|
return async (dispatch: AppDispatch, getState: () => RootState) => {
|
|
try {
|
|
dispatch(setLoading(true));
|
|
dispatch(setError(null));
|
|
|
|
// 这里可以添加实际的 API 调用逻辑
|
|
// 目前我们假设数据已经通过其他方式获取
|
|
|
|
dispatch(setLoading(false));
|
|
} catch (error) {
|
|
dispatch(setError(error instanceof Error ? error.message : '获取健康数据失败'));
|
|
dispatch(setLoading(false));
|
|
}
|
|
};
|
|
};
|
|
|
|
// Selectors
|
|
export const selectHealthDataByDate = (date: string) => (state: RootState) => state.health.dataByDate[date];
|
|
export const selectHealthLoading = (state: RootState) => state.health.loading;
|
|
export const selectHealthError = (state: RootState) => state.health.error;
|
|
export const selectLastUpdateTime = (state: RootState) => state.health.lastUpdateTime;
|
|
|
|
export default healthSlice.reducer; |