import { createAsyncThunk, createSlice, PayloadAction } from '@reduxjs/toolkit'; import * as healthProfileApi from '@/services/healthProfile'; 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; heartRate: number | null; activeEnergyBurned: number; activeCaloriesGoal: number; exerciseMinutes: number; exerciseMinutesGoal: number; standHours: number; standHoursGoal: number; } // 健康史数据类型定义 export interface HistoryItemDetail { id: string; name: string; date?: string; // ISO Date string isRecommendation?: boolean; } export interface HistoryData { [key: string]: { hasHistory: boolean | null; items: HistoryItemDetail[]; }; } export interface HealthState { // 按日期存储的历史数据 dataByDate: Record; // 健康史数据 historyData: HistoryData; // 加载状态 loading: boolean; error: string | null; // 最后更新时间 lastUpdateTime: string | null; } // 初始状态 const initialState: HealthState = { dataByDate: {}, historyData: { allergy: { hasHistory: null, items: [] }, disease: { hasHistory: null, items: [] }, surgery: { hasHistory: null, items: [] }, familyDisease: { hasHistory: null, items: [] }, }, loading: false, error: null, lastUpdateTime: null, }; const healthSlice = createSlice({ name: 'health', initialState, reducers: { // 设置加载状态 setLoading: (state, action: PayloadAction) => { state.loading = action.payload; }, // 设置错误信息 setError: (state, action: PayloadAction) => { 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) => { const date = action.payload; delete state.dataByDate[date]; }, // 清除所有健康数据 clearAllHealthData: (state) => { state.dataByDate = {}; state.error = null; state.lastUpdateTime = null; }, // 更新健康史数据(本地更新,用于乐观更新或离线模式) updateHistoryData: (state, action: PayloadAction<{ type: string; data: { hasHistory: boolean | null; items: HistoryItemDetail[]; }; }>) => { const { type, data } = action.payload; state.historyData[type] = data; state.lastUpdateTime = new Date().toISOString(); }, // 设置完整的健康史数据(从服务端同步) setHistoryData: (state, action: PayloadAction) => { state.historyData = action.payload; state.lastUpdateTime = new Date().toISOString(); }, // 清除健康史数据 clearHistoryData: (state) => { state.historyData = { allergy: { hasHistory: null, items: [] }, disease: { hasHistory: null, items: [] }, surgery: { hasHistory: null, items: [] }, familyDisease: { hasHistory: null, items: [] }, }; }, }, extraReducers: (builder) => { builder // 获取健康史 .addCase(fetchHealthHistory.pending, (state) => { state.loading = true; state.error = null; }) .addCase(fetchHealthHistory.fulfilled, (state, action) => { state.loading = false; // 转换服务端数据格式到本地格式 const serverData = action.payload; const categories = ['allergy', 'disease', 'surgery', 'familyDisease'] as const; categories.forEach(category => { if (serverData[category]) { state.historyData[category] = { hasHistory: serverData[category].hasHistory, items: serverData[category].items.map(item => ({ id: item.id, name: item.name, date: item.diagnosisDate, isRecommendation: item.isRecommendation, })), }; } }); state.lastUpdateTime = new Date().toISOString(); }) .addCase(fetchHealthHistory.rejected, (state, action) => { state.loading = false; state.error = action.payload as string; }) // 保存健康史分类 .addCase(saveHealthHistoryCategory.pending, (state) => { state.loading = true; state.error = null; }) .addCase(saveHealthHistoryCategory.fulfilled, (state, action) => { state.loading = false; const { category, data } = action.payload; // 更新对应分类的数据 state.historyData[category] = { hasHistory: data.hasHistory, items: data.items.map(item => ({ id: item.id, name: item.name, date: item.diagnosisDate, isRecommendation: item.isRecommendation, })), }; state.lastUpdateTime = new Date().toISOString(); }) .addCase(saveHealthHistoryCategory.rejected, (state, action) => { state.loading = false; state.error = action.payload as string; }) // 获取健康史进度 .addCase(fetchHealthHistoryProgress.rejected, (state, action) => { state.error = action.payload as string; }); }, }); // Action creators export const { setLoading, setError, setHealthData, clearHealthDataForDate, clearAllHealthData, updateHistoryData, setHistoryData, clearHistoryData, } = 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)); } }; }; // ==================== 健康史 API Thunks ==================== /** * 从服务端获取完整健康史数据 */ export const fetchHealthHistory = createAsyncThunk( 'health/fetchHistory', async (_, { rejectWithValue }) => { try { const data = await healthProfileApi.getHealthHistory(); return data; } catch (err: any) { return rejectWithValue(err?.message ?? '获取健康史失败'); } } ); /** * 保存健康史分类到服务端 */ export const saveHealthHistoryCategory = createAsyncThunk( 'health/saveHistoryCategory', async ( { category, data, }: { category: healthProfileApi.HealthHistoryCategory; data: healthProfileApi.UpdateHealthHistoryRequest; }, { rejectWithValue } ) => { try { const result = await healthProfileApi.updateHealthHistory(category, data); return { category, data: result }; } catch (err: any) { return rejectWithValue(err?.message ?? '保存健康史失败'); } } ); /** * 获取健康史完成进度 */ export const fetchHealthHistoryProgress = createAsyncThunk( 'health/fetchHistoryProgress', async (_, { rejectWithValue }) => { try { const data = await healthProfileApi.getHealthHistoryProgress(); return data; } catch (err: any) { return rejectWithValue(err?.message ?? '获取健康史进度失败'); } } ); // 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 const selectHistoryData = (state: RootState) => state.health.historyData; // 计算健康史完成度的 selector export const selectHealthHistoryProgress = (state: RootState) => { const historyData = state.health.historyData; const categories = ['allergy', 'disease', 'surgery', 'familyDisease']; let answeredCount = 0; categories.forEach(category => { const data = historyData[category]; // 只要回答了是否有历史(hasHistory !== null),就算已完成 if (data && data.hasHistory !== null) { answeredCount++; } }); return Math.round((answeredCount / categories.length) * 100); }; export default healthSlice.reducer;