feat: 增强任务管理功能,新增任务筛选和状态统计组件

- 在目标页面中集成任务筛选标签,支持按状态(全部、待完成、已完成)过滤任务
- 更新任务卡片,展示任务状态和优先级信息
- 新增任务进度卡片,统计各状态任务数量
- 优化空状态展示,根据筛选条件动态显示提示信息
- 引入新图标和图片资源,提升界面视觉效果
This commit is contained in:
2025-08-22 20:45:15 +08:00
parent 259f10540e
commit 9e719a9eda
8 changed files with 593 additions and 262 deletions

View File

@@ -1,5 +1,6 @@
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';
@@ -13,7 +14,7 @@ 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, RefreshControl, SafeAreaView, StatusBar, StyleSheet, Text, TouchableOpacity, View } from 'react-native';
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';
@@ -40,6 +41,7 @@ export default function GoalsScreen() {
const [showCreateModal, setShowCreateModal] = useState(false);
const [refreshing, setRefreshing] = useState(false);
const [selectedFilter, setSelectedFilter] = useState<TaskFilterType>('all');
// 页面聚焦时重新加载数据
useFocusEffect(
@@ -160,6 +162,30 @@ export default function GoalsScreen() {
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 }) => (
<TaskCard
@@ -171,16 +197,34 @@ export default function GoalsScreen() {
);
// 渲染空状态
const renderEmptyState = () => (
<View style={styles.emptyState}>
<Text style={[styles.emptyStateTitle, { color: colorTokens.text }]}>
</Text>
<Text style={[styles.emptyStateSubtitle, { color: colorTokens.textSecondary }]}>
</Text>
</View>
);
const renderEmptyState = () => {
let title = '暂无任务';
let subtitle = '创建目标后,系统会自动生成相应的任务';
if (selectedFilter === 'pending') {
title = '暂无待完成的任务';
subtitle = '当前没有待完成的任务';
} else if (selectedFilter === 'completed') {
title = '暂无已完成的任务';
subtitle = '完成一些任务后,它们会显示在这里';
}
return (
<View style={styles.emptyState}>
<Image
source={require('@/assets/images/task/ImageEmpty.png')}
style={styles.emptyStateImage}
resizeMode="contain"
/>
<Text style={[styles.emptyStateTitle, { color: colorTokens.text }]}>
{title}
</Text>
<Text style={[styles.emptyStateSubtitle, { color: colorTokens.textSecondary }]}>
{subtitle}
</Text>
</View>
);
};
// 渲染加载更多
const renderLoadMore = () => {
@@ -209,39 +253,71 @@ export default function GoalsScreen() {
end={{ x: 1, y: 1 }}
/>
{/* 装饰性圆圈 */}
<View style={styles.decorativeCircle1} />
<View style={styles.decorativeCircle2} />
<View style={{
position: 'absolute',
top: 0,
left: 0,
right: 0,
backgroundColor: '#7A5AF8',
height: 233,
borderBottomLeftRadius: 24,
borderBottomRightRadius: 24,
}}>
{/* 右下角图片 */}
<Image
source={require('@/assets/images/task/imageTodo.png')}
style={styles.bottomRightImage}
resizeMode="contain"
/>
</View>
<View style={styles.content}>
{/* 标题区域 */}
<View style={styles.header}>
<Text style={[styles.pageTitle, { color: colorTokens.text }]}>
<View>
<Text style={[styles.pageTitle, { color: '#FFFFFF' }]}>
</Text>
<Text style={[styles.pageTitle2, { color: '#FFFFFF' }]}>
</Text>
<View style={styles.headerButtons}>
<TouchableOpacity
style={styles.goalsButton}
onPress={handleNavigateToGoals}
>
<MaterialIcons name="flag" size={16} color="#0EA5E9" />
</TouchableOpacity>
<TouchableOpacity
style={styles.addButton}
onPress={() => setShowCreateModal(true)}
>
<Text style={styles.addButtonText}>+</Text>
</TouchableOpacity>
</View>
</View>
{/* 任务进度卡片 */}
<TaskProgressCard tasks={tasks} />
<View >
<TaskProgressCard
tasks={tasks}
headerButtons={
<View style={styles.cardHeaderButtons}>
<TouchableOpacity
style={[styles.cardGoalsButton, { borderColor: colorTokens.primary }]}
onPress={handleNavigateToGoals}
>
<MaterialIcons name="flag" size={16} color={colorTokens.primary} />
</TouchableOpacity>
<TouchableOpacity
style={[styles.cardAddButton, { backgroundColor: colorTokens.primary }]}
onPress={() => setShowCreateModal(true)}
>
<Text style={styles.cardAddButtonText}>+</Text>
</TouchableOpacity>
</View>
}
/>
</View>
{/* 任务筛选标签 */}
<TaskFilterTabs
selectedFilter={selectedFilter}
onFilterChange={handleFilterChange}
taskCounts={taskCounts}
/>
{/* 任务列表 */}
<View style={styles.taskListContainer}>
<FlatList
data={tasks}
data={filteredTasks}
renderItem={renderTaskItem}
keyExtractor={(item) => item.id}
contentContainerStyle={styles.taskList}
@@ -340,6 +416,12 @@ const styles = StyleSheet.create({
fontWeight: '800',
marginBottom: 4,
},
pageTitle2: {
fontSize: 16,
fontWeight: '400',
color: '#FFFFFF',
lineHeight: 24,
},
addButton: {
width: 30,
height: 30,
@@ -362,7 +444,6 @@ const styles = StyleSheet.create({
taskListContainer: {
flex: 1,
backgroundColor: 'rgba(255, 255, 255, 0.95)',
borderTopLeftRadius: 24,
borderTopRightRadius: 24,
overflow: 'hidden',
@@ -377,6 +458,11 @@ const styles = StyleSheet.create({
justifyContent: 'center',
paddingVertical: 60,
},
emptyStateImage: {
width: 223,
height: 59,
marginBottom: 20,
},
emptyStateTitle: {
fontSize: 18,
fontWeight: '600',
@@ -395,4 +481,40 @@ const styles = StyleSheet.create({
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,
},
});