feat: 增强任务管理功能,新增任务筛选和状态统计组件
- 在目标页面中集成任务筛选标签,支持按状态(全部、待完成、已完成)过滤任务 - 更新任务卡片,展示任务状态和优先级信息 - 新增任务进度卡片,统计各状态任务数量 - 优化空状态展示,根据筛选条件动态显示提示信息 - 引入新图标和图片资源,提升界面视觉效果
This commit is contained in:
@@ -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,
|
||||
},
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user