- 从 healthSlice 和 health.ts 中移除 sleepDuration 字段及相关获取逻辑 - 将 SleepCard 改为按需异步获取睡眠数据,支持传入指定日期 - 睡眠详情页改为通过路由参数接收日期,支持查看历史记录 - 移除 statistics 页面对 sleepDuration 的直接依赖,统一由 SleepCard 管理 - 删除未使用的 SleepStageChart 组件,简化页面结构
127 lines
3.3 KiB
TypeScript
127 lines
3.3 KiB
TypeScript
import { HourlyStepData } from '@/utils/health';
|
|
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 {
|
|
steps: number | null;
|
|
activeCalories: number | null;
|
|
basalEnergyBurned: number | null;
|
|
hrv: number | null;
|
|
oxygenSaturation: number | null;
|
|
heartRate: number | null;
|
|
activeEnergyBurned: number;
|
|
activeCaloriesGoal: number;
|
|
exerciseMinutes: number;
|
|
exerciseMinutesGoal: number;
|
|
standHours: number;
|
|
standHoursGoal: number;
|
|
hourlySteps: HourlyStepData[];
|
|
}
|
|
|
|
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; |