import CreateGoalModal from '@/components/CreateGoalModal'; import { TaskCard } from '@/components/TaskCard'; import { TaskFilterTabs, TaskFilterType } from '@/components/TaskFilterTabs'; import { TaskProgressCard } from '@/components/TaskProgressCard'; import { Colors } from '@/constants/Colors'; import { useAppDispatch, useAppSelector } from '@/hooks/redux'; import { useColorScheme } from '@/hooks/useColorScheme'; import { clearErrors, createGoal } from '@/store/goalsSlice'; import { clearErrors as clearTaskErrors, completeTask, fetchTasks, loadMoreTasks, skipTask } from '@/store/tasksSlice'; import { CreateGoalRequest, TaskListItem } from '@/types/goals'; import MaterialIcons from '@expo/vector-icons/MaterialIcons'; import { useFocusEffect } from '@react-navigation/native'; import dayjs from 'dayjs'; import { LinearGradient } from 'expo-linear-gradient'; import { useRouter } from 'expo-router'; import React, { useCallback, useEffect, useState } from 'react'; import { Alert, FlatList, Image, RefreshControl, SafeAreaView, StatusBar, StyleSheet, Text, TouchableOpacity, View } from 'react-native'; export default function GoalsScreen() { const theme = (useColorScheme() ?? 'light') as 'light' | 'dark'; const colorTokens = Colors[theme]; const dispatch = useAppDispatch(); const router = useRouter(); // Redux状态 const { tasks, tasksLoading, tasksError, tasksPagination, completeLoading, completeError, skipLoading, skipError, } = useAppSelector((state) => state.tasks); const { createLoading, createError } = useAppSelector((state) => state.goals); const [showCreateModal, setShowCreateModal] = useState(false); const [refreshing, setRefreshing] = useState(false); const [selectedFilter, setSelectedFilter] = useState('all'); // 页面聚焦时重新加载数据 useFocusEffect( useCallback(() => { console.log('useFocusEffect - loading tasks'); loadTasks(); }, [dispatch]) ); // 加载任务列表 const loadTasks = async () => { try { await dispatch(fetchTasks({ startDate: dayjs().startOf('day').toISOString(), endDate: dayjs().endOf('day').toISOString(), })).unwrap(); } catch (error) { console.error('Failed to load tasks:', error); } }; // 下拉刷新 const onRefresh = async () => { setRefreshing(true); try { await loadTasks(); } finally { setRefreshing(false); } }; // 加载更多任务 const handleLoadMoreTasks = async () => { if (tasksPagination.hasMore && !tasksLoading) { try { await dispatch(loadMoreTasks()).unwrap(); } catch (error) { console.error('Failed to load more tasks:', error); } } }; // 处理错误提示 useEffect(() => { console.log('tasksError', tasksError); console.log('createError', createError); console.log('completeError', completeError); console.log('skipError', skipError); if (tasksError) { Alert.alert('错误', tasksError); dispatch(clearTaskErrors()); } if (createError) { Alert.alert('创建失败', createError); dispatch(clearErrors()); } if (completeError) { Alert.alert('完成失败', completeError); dispatch(clearTaskErrors()); } if (skipError) { Alert.alert('跳过失败', skipError); dispatch(clearTaskErrors()); } }, [tasksError, createError, completeError, skipError, dispatch]); // 创建目标处理函数 const handleCreateGoal = async (goalData: CreateGoalRequest) => { try { await dispatch(createGoal(goalData)).unwrap(); setShowCreateModal(false); Alert.alert('成功', '目标创建成功!'); // 创建目标后重新加载任务列表 loadTasks(); } catch (error) { // 错误已在useEffect中处理 } }; // 任务点击处理 const handleTaskPress = (task: TaskListItem) => { console.log('Task pressed:', task.title); // 这里可以导航到任务详情页面 }; // 完成任务处理 const handleCompleteTask = async (task: TaskListItem) => { try { await dispatch(completeTask({ taskId: task.id, completionData: { count: 1, notes: '通过任务卡片完成' } })).unwrap(); } catch (error) { Alert.alert('错误', '完成任务失败'); } }; // 跳过任务处理 const handleSkipTask = async (task: TaskListItem) => { try { await dispatch(skipTask({ taskId: task.id, skipData: { reason: '用户主动跳过' } })).unwrap(); } catch (error) { Alert.alert('错误', '跳过任务失败'); } }; // 导航到目标管理页面 const handleNavigateToGoals = () => { router.push('/goals-detail'); }; // 计算各状态的任务数量 const taskCounts = { all: tasks.length, pending: tasks.filter(task => task.status === 'pending').length, completed: tasks.filter(task => task.status === 'completed').length, }; // 根据筛选条件过滤任务 const filteredTasks = React.useMemo(() => { switch (selectedFilter) { case 'pending': return tasks.filter(task => task.status === 'pending'); case 'completed': return tasks.filter(task => task.status === 'completed'); default: return tasks; } }, [tasks, selectedFilter]); // 处理筛选变化 const handleFilterChange = (filter: TaskFilterType) => { setSelectedFilter(filter); }; // 渲染任务项 const renderTaskItem = ({ item }: { item: TaskListItem }) => ( ); // 渲染空状态 const renderEmptyState = () => { let title = '暂无任务'; let subtitle = '创建目标后,系统会自动生成相应的任务'; if (selectedFilter === 'pending') { title = '暂无待完成的任务'; subtitle = '当前没有待完成的任务'; } else if (selectedFilter === 'completed') { title = '暂无已完成的任务'; subtitle = '完成一些任务后,它们会显示在这里'; } return ( {title} {subtitle} ); }; // 渲染加载更多 const renderLoadMore = () => { if (!tasksPagination.hasMore) return null; return ( {tasksLoading ? '加载中...' : '上拉加载更多'} ); }; return ( {/* 背景渐变 */} {/* 右下角图片 */} {/* 标题区域 */} 等待完成 让我们检查你的目标! {/* 任务进度卡片 */} setShowCreateModal(true)} > + } /> {/* 任务筛选标签 */} {/* 任务列表 */} item.id} contentContainerStyle={styles.taskList} showsVerticalScrollIndicator={false} refreshControl={ } onEndReached={handleLoadMoreTasks} onEndReachedThreshold={0.1} ListEmptyComponent={renderEmptyState} ListFooterComponent={renderLoadMore} /> {/* 创建目标弹窗 */} setShowCreateModal(false)} onSubmit={handleCreateGoal} loading={createLoading} /> ); } const styles = StyleSheet.create({ container: { flex: 1, }, gradientBackground: { position: 'absolute', left: 0, right: 0, top: 0, bottom: 0, opacity: 0.6, }, decorativeCircle1: { position: 'absolute', top: -20, right: -20, width: 60, height: 60, borderRadius: 30, backgroundColor: '#0EA5E9', opacity: 0.1, }, decorativeCircle2: { position: 'absolute', bottom: -15, left: -15, width: 40, height: 40, borderRadius: 20, backgroundColor: '#0EA5E9', opacity: 0.05, }, content: { flex: 1, }, header: { flexDirection: 'row', alignItems: 'center', justifyContent: 'space-between', paddingHorizontal: 20, paddingTop: 20, paddingBottom: 16, }, headerButtons: { flexDirection: 'row', alignItems: 'center', gap: 12, }, goalsButton: { flexDirection: 'row', alignItems: 'center', gap: 4, paddingHorizontal: 12, paddingVertical: 8, borderRadius: 20, backgroundColor: 'rgba(255, 255, 255, 0.8)', shadowColor: '#000', shadowOffset: { width: 0, height: 2 }, shadowOpacity: 0.1, shadowRadius: 4, elevation: 3, }, pageTitle: { fontSize: 28, fontWeight: '800', marginBottom: 4, }, pageTitle2: { fontSize: 16, fontWeight: '400', color: '#FFFFFF', lineHeight: 24, }, addButton: { width: 30, height: 30, borderRadius: 20, backgroundColor: '#0EA5E9', alignItems: 'center', justifyContent: 'center', shadowColor: '#000', shadowOffset: { width: 0, height: 2 }, shadowOpacity: 0.1, shadowRadius: 4, elevation: 3, }, addButtonText: { color: '#FFFFFF', fontSize: 22, fontWeight: '600', lineHeight: 22, }, taskListContainer: { flex: 1, borderTopLeftRadius: 24, borderTopRightRadius: 24, overflow: 'hidden', }, taskList: { paddingHorizontal: 20, paddingTop: 20, paddingBottom: 20, }, emptyState: { alignItems: 'center', justifyContent: 'center', paddingVertical: 60, }, emptyStateImage: { width: 223, height: 59, marginBottom: 20, }, emptyStateTitle: { fontSize: 18, fontWeight: '600', marginBottom: 8, }, emptyStateSubtitle: { fontSize: 14, textAlign: 'center', lineHeight: 20, }, loadMoreContainer: { alignItems: 'center', paddingVertical: 20, }, loadMoreText: { fontSize: 14, fontWeight: '500', }, bottomRightImage: { position: 'absolute', top: 56, right: 36, width: 80, height: 80, }, // 任务进度卡片中的按钮样式 cardHeaderButtons: { flexDirection: 'row', alignItems: 'center', gap: 8, }, cardGoalsButton: { flexDirection: 'row', alignItems: 'center', gap: 4, paddingHorizontal: 10, paddingVertical: 6, borderRadius: 16, backgroundColor: '#F3F4F6', borderWidth: 1, }, cardAddButton: { width: 28, height: 28, borderRadius: 14, alignItems: 'center', justifyContent: 'center', }, cardAddButtonText: { color: '#FFFFFF', fontSize: 18, fontWeight: '600', lineHeight: 18, }, });