import { tasksApi } from '@/services/tasksApi'; import { CompleteTaskRequest, GetTasksQuery, SkipTaskRequest, TaskListItem, TaskStats, } from '@/types/goals'; import { createAsyncThunk, createSlice, PayloadAction } from '@reduxjs/toolkit'; // 任务管理状态类型 export interface TasksState { // 任务列表 tasks: TaskListItem[]; tasksLoading: boolean; tasksError: string | null; tasksPagination: { page: number; pageSize: number; total: number; hasMore: boolean; }; // 任务统计 stats: TaskStats | null; statsLoading: boolean; statsError: string | null; // 完成任务 completeLoading: boolean; completeError: string | null; // 跳过任务 skipLoading: boolean; skipError: string | null; // 筛选和搜索 filters: GetTasksQuery; } const initialState: TasksState = { tasks: [], tasksLoading: false, tasksError: null, tasksPagination: { page: 1, pageSize: 20, total: 0, hasMore: false, }, stats: null, statsLoading: false, statsError: null, completeLoading: false, completeError: null, skipLoading: false, skipError: null, filters: { page: 1, pageSize: 20, }, }; // 异步操作 /** * 获取任务列表 */ export const fetchTasks = createAsyncThunk( 'tasks/fetchTasks', async (query: GetTasksQuery = {}, { rejectWithValue }) => { try { console.log('fetchTasks', fetchTasks); const response = await tasksApi.getTasks(query); console.log('fetchTasks response', response); return { query, response }; } catch (error: any) { return rejectWithValue(error.message || '获取任务列表失败'); } } ); /** * 加载更多任务 */ export const loadMoreTasks = createAsyncThunk( 'tasks/loadMoreTasks', async (_, { getState, rejectWithValue }) => { try { const state = getState() as { tasks: TasksState }; const { filters, tasksPagination } = state.tasks; if (!tasksPagination.hasMore) { return { tasks: [], pagination: tasksPagination }; } const query = { ...filters, page: tasksPagination.page + 1, }; const response = await tasksApi.getTasks(query); console.log('loadMoreTasks response', response); return { query, response }; } catch (error: any) { return rejectWithValue(error.message || '加载更多任务失败'); } } ); /** * 完成任务 */ export const completeTask = createAsyncThunk( 'tasks/completeTask', async ({ taskId, completionData }: { taskId: string; completionData?: CompleteTaskRequest }, { rejectWithValue }) => { try { const response = await tasksApi.completeTask(taskId, completionData); console.log('completeTask response', response); return response; } catch (error: any) { return rejectWithValue(error.message || '完成任务失败'); } } ); /** * 跳过任务 */ export const skipTask = createAsyncThunk( 'tasks/skipTask', async ({ taskId, skipData }: { taskId: string; skipData?: SkipTaskRequest }, { rejectWithValue }) => { try { const response = await tasksApi.skipTask(taskId, skipData); console.log('skipTask response', response); return response; } catch (error: any) { return rejectWithValue(error.message || '跳过任务失败'); } } ); /** * 获取任务统计 */ export const fetchTaskStats = createAsyncThunk( 'tasks/fetchTaskStats', async (goalId: string, { rejectWithValue }) => { try { const response = await tasksApi.getTaskStats(goalId); console.log('fetchTaskStats response', response); return response; } catch (error: any) { return rejectWithValue(error.message || '获取任务统计失败'); } } ); // Redux Slice const tasksSlice = createSlice({ name: 'tasks', initialState, reducers: { // 清除错误 clearErrors: (state) => { state.tasksError = null; state.completeError = null; state.skipError = null; state.statsError = null; }, // 更新筛选条件 updateFilters: (state, action: PayloadAction>) => { state.filters = { ...state.filters, ...action.payload }; }, // 重置筛选条件 resetFilters: (state) => { state.filters = { page: 1, pageSize: 20, }; }, // 乐观更新任务完成状态 optimisticCompleteTask: (state, action: PayloadAction<{ taskId: string; count?: number }>) => { const { taskId, count = 1 } = action.payload; const task = state.tasks.find(t => t.id === taskId); if (task) { const newCount = Math.min(task.currentCount + count, task.targetCount); task.currentCount = newCount; task.progressPercentage = Math.round((newCount / task.targetCount) * 100); if (newCount >= task.targetCount) { task.status = 'completed'; task.completedAt = new Date().toISOString(); } else if (newCount > 0) { task.status = 'in_progress'; } } }, }, extraReducers: (builder) => { builder // 获取任务列表 .addCase(fetchTasks.pending, (state) => { state.tasksLoading = true; state.tasksError = null; }) .addCase(fetchTasks.fulfilled, (state, action) => { state.tasksLoading = false; const { query, response } = action.payload; // 如果是第一页,替换数据;否则追加数据 state.tasks = response.list; console.log('state.tasks', state.tasks); state.tasksPagination = { page: response.page, pageSize: response.pageSize, total: response.total, hasMore: response.page * response.pageSize < response.total, }; }) .addCase(fetchTasks.rejected, (state, action) => { state.tasksLoading = false; state.tasksError = action.payload as string; }) // 加载更多任务 .addCase(loadMoreTasks.pending, (state) => { state.tasksLoading = true; }) .addCase(loadMoreTasks.fulfilled, (state, action) => { state.tasksLoading = false; const { response } = action.payload; if (!response) { return; } state.tasks = [...state.tasks, ...response.list]; state.tasksPagination = { page: response.page, pageSize: response.pageSize, total: response.total, hasMore: response.page * response.pageSize < response.total, }; }) .addCase(loadMoreTasks.rejected, (state, action) => { state.tasksLoading = false; state.tasksError = action.payload as string; }) // 完成任务 .addCase(completeTask.pending, (state) => { state.completeLoading = true; state.completeError = null; }) .addCase(completeTask.fulfilled, (state, action) => { state.completeLoading = false; // 更新任务列表中的对应任务 const updatedTask = action.payload; const index = state.tasks.findIndex(t => t.id === updatedTask.id); if (index !== -1) { state.tasks[index] = updatedTask; } }) .addCase(completeTask.rejected, (state, action) => { state.completeLoading = false; state.completeError = action.payload as string; }) // 跳过任务 .addCase(skipTask.pending, (state) => { state.skipLoading = true; state.skipError = null; }) .addCase(skipTask.fulfilled, (state, action) => { state.skipLoading = false; // 更新任务列表中的对应任务 const updatedTask = action.payload; const index = state.tasks.findIndex(t => t.id === updatedTask.id); if (index !== -1) { state.tasks[index] = updatedTask; } }) .addCase(skipTask.rejected, (state, action) => { state.skipLoading = false; state.skipError = action.payload as string; }) // 获取任务统计 .addCase(fetchTaskStats.pending, (state) => { state.statsLoading = true; state.statsError = null; }) .addCase(fetchTaskStats.fulfilled, (state, action) => { state.statsLoading = false; state.stats = action.payload; }) .addCase(fetchTaskStats.rejected, (state, action) => { state.statsLoading = false; state.statsError = action.payload as string; }); }, }); export const { clearErrors, updateFilters, resetFilters, optimisticCompleteTask, } = tasksSlice.actions; export default tasksSlice.reducer;