import { createMoodCheckin, CreateMoodCheckinDto, deleteMoodCheckin, DeleteMoodCheckinDto, getDailyMoodCheckins, getMoodCheckinsHistory, getMoodStatistics, MoodCheckin, MoodType, updateMoodCheckin, UpdateMoodCheckinDto } from '@/services/moodCheckins'; import { createAsyncThunk, createSlice, PayloadAction } from '@reduxjs/toolkit'; import dayjs from 'dayjs'; // 状态接口 interface MoodState { // 按日期存储的心情记录 moodRecords: Record; // 当前选中的日期 selectedDate: string; // 当前选中的心情记录 selectedMoodRecord: MoodCheckin | null; // 加载状态 loading: { daily: boolean; history: boolean; statistics: boolean; create: boolean; update: boolean; delete: boolean; }; // 错误信息 error: string | null; // 统计数据 statistics: { totalCheckins: number; averageIntensity: number; moodDistribution: Record; mostFrequentMood: MoodType | null; } | null; } // 初始状态 const initialState: MoodState = { moodRecords: {}, selectedDate: dayjs().format('YYYY-MM-DD'), selectedMoodRecord: null, loading: { daily: false, history: false, statistics: false, create: false, update: false, delete: false, }, error: null, statistics: null, }; // 异步 actions export const fetchDailyMoodCheckins = createAsyncThunk( 'mood/fetchDailyMoodCheckins', async (date: string) => { const checkins = await getDailyMoodCheckins(date); return { date, checkins }; } ); export const fetchMoodHistory = createAsyncThunk( 'mood/fetchMoodHistory', async (params: { startDate: string; endDate: string; moodType?: MoodType }) => { const checkins = await getMoodCheckinsHistory(params); return { params, checkins }; } ); export const fetchMoodStatistics = createAsyncThunk( 'mood/fetchMoodStatistics', async (params: { startDate: string; endDate: string }) => { const statistics = await getMoodStatistics(params); return statistics; } ); export const createMoodRecord = createAsyncThunk( 'mood/createMoodRecord', async (dto: CreateMoodCheckinDto) => { const newRecord = await createMoodCheckin(dto); return newRecord; } ); export const updateMoodRecord = createAsyncThunk( 'mood/updateMoodRecord', async (dto: UpdateMoodCheckinDto) => { const updatedRecord = await updateMoodCheckin(dto); return updatedRecord; } ); export const deleteMoodRecord = createAsyncThunk( 'mood/deleteMoodRecord', async (dto: DeleteMoodCheckinDto) => { await deleteMoodCheckin(dto); return dto.id; } ); // 创建 slice const moodSlice = createSlice({ name: 'mood', initialState, reducers: { // 设置选中的日期 setSelectedDate: (state, action: PayloadAction) => { state.selectedDate = action.payload; // 如果该日期没有记录,设置为 null const records = state.moodRecords[action.payload]; state.selectedMoodRecord = records && records.length > 0 ? records[0] : null; }, // 设置选中的心情记录 setSelectedMoodRecord: (state, action: PayloadAction) => { state.selectedMoodRecord = action.payload; }, // 清除错误 clearError: (state) => { state.error = null; }, // 清除统计数据 clearStatistics: (state) => { state.statistics = null; }, // 清除所有数据 clearMoodData: (state) => { state.moodRecords = {}; state.selectedMoodRecord = null; state.statistics = null; state.error = null; }, }, extraReducers: (builder) => { // fetchDailyMoodCheckins builder .addCase(fetchDailyMoodCheckins.pending, (state) => { state.loading.daily = true; state.error = null; }) .addCase(fetchDailyMoodCheckins.fulfilled, (state, action) => { state.loading.daily = false; const { date, checkins } = action.payload; state.moodRecords[date] = checkins; // 如果是当前选中的日期,更新选中的记录 if (date === state.selectedDate) { state.selectedMoodRecord = checkins.length > 0 ? checkins[0] : null; } }) .addCase(fetchDailyMoodCheckins.rejected, (state, action) => { state.loading.daily = false; state.error = action.error.message || '获取心情记录失败'; }); // fetchMoodHistory builder .addCase(fetchMoodHistory.pending, (state) => { state.loading.history = true; state.error = null; }) .addCase(fetchMoodHistory.fulfilled, (state, action) => { state.loading.history = false; const { checkins } = action.payload; // 将历史记录按日期分组存储 checkins.forEach(checkin => { const date = checkin.checkinDate; if (!state.moodRecords[date]) { state.moodRecords[date] = []; } // 检查是否已存在相同 ID 的记录 const existingIndex = state.moodRecords[date].findIndex(r => r.id === checkin.id); if (existingIndex >= 0) { state.moodRecords[date][existingIndex] = checkin; } else { state.moodRecords[date].push(checkin); } }); }) .addCase(fetchMoodHistory.rejected, (state, action) => { state.loading.history = false; state.error = action.error.message || '获取心情历史失败'; }); // fetchMoodStatistics builder .addCase(fetchMoodStatistics.pending, (state) => { state.loading.statistics = true; state.error = null; }) .addCase(fetchMoodStatistics.fulfilled, (state, action) => { state.loading.statistics = false; state.statistics = action.payload; }) .addCase(fetchMoodStatistics.rejected, (state, action) => { state.loading.statistics = false; state.error = action.error.message || '获取心情统计失败'; }); // createMoodRecord builder .addCase(createMoodRecord.pending, (state) => { state.loading.create = true; state.error = null; }) .addCase(createMoodRecord.fulfilled, (state, action) => { state.loading.create = false; const newRecord = action.payload; const date = newRecord.checkinDate; // 添加到对应日期的记录中 if (!state.moodRecords[date]) { state.moodRecords[date] = []; } state.moodRecords[date].unshift(newRecord); // 添加到开头 // 如果是当前选中的日期,更新选中的记录 if (date === state.selectedDate) { state.selectedMoodRecord = newRecord; } }) .addCase(createMoodRecord.rejected, (state, action) => { state.loading.create = false; state.error = action.error.message || '创建心情记录失败'; }); // updateMoodRecord builder .addCase(updateMoodRecord.pending, (state) => { state.loading.update = true; state.error = null; }) .addCase(updateMoodRecord.fulfilled, (state, action) => { state.loading.update = false; const updatedRecord = action.payload; const date = updatedRecord.checkinDate; // 更新对应日期的记录 if (state.moodRecords[date]) { const index = state.moodRecords[date].findIndex(r => r.id === updatedRecord.id); if (index >= 0) { state.moodRecords[date][index] = updatedRecord; } } // 如果是当前选中的记录,更新选中的记录 if (state.selectedMoodRecord?.id === updatedRecord.id) { state.selectedMoodRecord = updatedRecord; } }) .addCase(updateMoodRecord.rejected, (state, action) => { state.loading.update = false; state.error = action.error.message || '更新心情记录失败'; }); // deleteMoodRecord builder .addCase(deleteMoodRecord.pending, (state) => { state.loading.delete = true; state.error = null; }) .addCase(deleteMoodRecord.fulfilled, (state, action) => { state.loading.delete = false; const deletedId = action.payload; // 从所有日期的记录中删除 Object.keys(state.moodRecords).forEach(date => { state.moodRecords[date] = state.moodRecords[date].filter(r => r.id !== deletedId); }); // 如果是当前选中的记录被删除,清空选中的记录 if (state.selectedMoodRecord?.id === deletedId) { state.selectedMoodRecord = null; } }) .addCase(deleteMoodRecord.rejected, (state, action) => { state.loading.delete = false; state.error = action.error.message || '删除心情记录失败'; }); }, }); // 导出 actions export const { setSelectedDate, setSelectedMoodRecord, clearError, clearStatistics, clearMoodData, } = moodSlice.actions; // 导出 reducer export default moodSlice.reducer; // 导出选择器 export const selectMoodState = (state: { mood: MoodState }) => state.mood; export const selectMoodRecords = (state: { mood: MoodState }) => state.mood.moodRecords; export const selectSelectedDate = (state: { mood: MoodState }) => state.mood.selectedDate; export const selectSelectedMoodRecord = (state: { mood: MoodState }) => state.mood.selectedMoodRecord; export const selectMoodLoading = (state: { mood: MoodState }) => state.mood.loading; export const selectMoodError = (state: { mood: MoodState }) => state.mood.error; export const selectMoodStatistics = (state: { mood: MoodState }) => state.mood.statistics; // 获取指定日期的心情记录 export const selectMoodRecordsByDate = (date: string) => (state: { mood: MoodState }) => { return state.mood.moodRecords[date] || []; }; // 获取指定日期的最新心情记录 export const selectLatestMoodRecordByDate = (date: string) => (state: { mood: MoodState }) => { const records = state.mood.moodRecords[date] || []; return records.length > 0 ? records[0] : null; };