From 9e719a9edad914e53f43019124ae9c8273d6a7aa Mon Sep 17 00:00:00 2001 From: richarjiang Date: Fri, 22 Aug 2025 20:45:15 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E5=A2=9E=E5=BC=BA=E4=BB=BB=E5=8A=A1?= =?UTF-8?q?=E7=AE=A1=E7=90=86=E5=8A=9F=E8=83=BD=EF=BC=8C=E6=96=B0=E5=A2=9E?= =?UTF-8?q?=E4=BB=BB=E5=8A=A1=E7=AD=9B=E9=80=89=E5=92=8C=E7=8A=B6=E6=80=81?= =?UTF-8?q?=E7=BB=9F=E8=AE=A1=E7=BB=84=E4=BB=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 在目标页面中集成任务筛选标签,支持按状态(全部、待完成、已完成)过滤任务 - 更新任务卡片,展示任务状态和优先级信息 - 新增任务进度卡片,统计各状态任务数量 - 优化空状态展示,根据筛选条件动态显示提示信息 - 引入新图标和图片资源,提升界面视觉效果 --- app/(tabs)/goals.tsx | 186 +++++++++++++--- assets/images/task/ImageEmpty.png | Bin 0 -> 21036 bytes assets/images/task/iconTaskHeader.png | Bin 0 -> 1077 bytes assets/images/task/imageTodo.png | Bin 0 -> 6614 bytes components/TaskCard.tsx | 299 ++++++++++++++------------ components/TaskFilterTabs.tsx | 175 +++++++++++++++ components/TaskProgressCard.tsx | 189 ++++++++-------- constants/Colors.ts | 6 +- 8 files changed, 593 insertions(+), 262 deletions(-) create mode 100644 assets/images/task/ImageEmpty.png create mode 100644 assets/images/task/iconTaskHeader.png create mode 100644 assets/images/task/imageTodo.png create mode 100644 components/TaskFilterTabs.tsx diff --git a/app/(tabs)/goals.tsx b/app/(tabs)/goals.tsx index c5ec085..d607974 100644 --- a/app/(tabs)/goals.tsx +++ b/app/(tabs)/goals.tsx @@ -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('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 }) => ( ( - - - 暂无任务 - - - 创建目标后,系统会自动生成相应的任务 - - - ); + const renderEmptyState = () => { + let title = '暂无任务'; + let subtitle = '创建目标后,系统会自动生成相应的任务'; + + if (selectedFilter === 'pending') { + title = '暂无待完成的任务'; + subtitle = '当前没有待完成的任务'; + } else if (selectedFilter === 'completed') { + title = '暂无已完成的任务'; + subtitle = '完成一些任务后,它们会显示在这里'; + } + + return ( + + + + {title} + + + {subtitle} + + + ); + }; // 渲染加载更多 const renderLoadMore = () => { @@ -209,39 +253,71 @@ export default function GoalsScreen() { end={{ x: 1, y: 1 }} /> - {/* 装饰性圆圈 */} - - + + {/* 右下角图片 */} + + {/* 标题区域 */} - - 任务 + + + 等待完成 + + + 让我们检查你的目标! - - - - - setShowCreateModal(true)} - > - + - {/* 任务进度卡片 */} - + + + + + + setShowCreateModal(true)} + > + + + + + } + /> + + + {/* 任务筛选标签 */} + {/* 任务列表 */} 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, + }, }); diff --git a/assets/images/task/ImageEmpty.png b/assets/images/task/ImageEmpty.png new file mode 100644 index 0000000000000000000000000000000000000000..449bb85852645a3f33378db6717ece5ff2c5102e GIT binary patch literal 21036 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 T%mt~rBblxyOyiT<^U(hQfbm*J literal 0 HcmV?d00001 diff --git a/assets/images/task/iconTaskHeader.png b/assets/images/task/iconTaskHeader.png new file mode 100644 index 0000000000000000000000000000000000000000..b43e318189dcde2cc160c20273faa72aabc53a4f GIT binary patch literal 1077 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 b@8#1;am>T`8|}2;Fmw=Yqx%(_) = ({ } }; - const getCategoryColor = (category?: string) => { - if (!category) return '#6B7280'; - if (category.includes('运动') || category.includes('健身')) return '#EF4444'; - if (category.includes('工作')) return '#3B82F6'; - if (category.includes('健康')) return '#10B981'; - if (category.includes('财务')) return '#F59E0B'; - return '#6B7280'; + const getPriorityColor = (status: string) => { + switch (status) { + case 'overdue': + return '#EF4444'; // High - 过期任务 + case 'in_progress': + return '#F59E0B'; // Medium - 进行中 + case 'completed': + return '#10B981'; // Low - 已完成 + default: + return '#6B7280'; // Default - 待开始 + } }; + const getPriorityText = (status: string) => { + switch (status) { + case 'overdue': + return '高'; + case 'in_progress': + return '中'; + case 'completed': + return '低'; + default: + return ''; + } + }; + + + const formatDate = (dateString: string) => { const date = new Date(dateString); - const today = new Date(); - const tomorrow = new Date(today); - tomorrow.setDate(tomorrow.getDate() + 1); - - if (date.toDateString() === today.toDateString()) { - return '今天'; - } else if (date.toDateString() === tomorrow.toDateString()) { - return '明天'; - } else { - return date.toLocaleDateString('zh-CN', { month: 'short', day: 'numeric' }); - } + const month = date.toLocaleDateString('zh-CN', { month: 'short' }); + const day = date.getDate(); + return `${day} ${month}`; }; return ( @@ -80,71 +92,74 @@ export const TaskCard: React.FC = ({ onPress={() => onPress?.(task)} activeOpacity={0.7} > + {/* 头部区域 */} - + + + + {task.title} - {task.goal?.category && ( - - {task.goal?.category} - - )} - - - {getStatusText(task.status)} - {task.description && ( - - {task.description} - - )} - - - - - 进度: {task.currentCount}/{task.targetCount} - - - {task.progressPercentage}% - + {/* 状态和优先级标签 */} + + + + {getStatusText(task.status)} - - + + + {getPriorityText(task.status)} + {/* 进度条 */} + + + + + {/* 底部信息 */} - - {formatDate(task.startDate)} - - - {task.status === 'pending' || task.status === 'in_progress' ? ( - - onSkip?.(task)} - > - 跳过 - - onComplete?.(task)} - > - 完成 - + + {/* 模拟团队成员头像 */} + + + A + + + B + + + C + - ) : null} + + + + + + {formatDate(task.startDate)} + + + + 2 + + ); @@ -162,99 +177,119 @@ const styles = StyleSheet.create({ elevation: 3, }, header: { - flexDirection: 'row', - justifyContent: 'space-between', - alignItems: 'flex-start', - marginBottom: 8, + marginBottom: 12, }, - titleContainer: { - flex: 1, - marginRight: 8, + titleSection: { + flexDirection: 'row', + alignItems: 'center', + gap: 12, + }, + iconContainer: { + width: 32, + height: 32, + borderRadius: 16, + backgroundColor: '#7A5AF8', + alignItems: 'center', + justifyContent: 'center', + flexShrink: 0, + }, + taskIcon: { + width: 20, + height: 20, }, title: { fontSize: 16, fontWeight: '600', - marginBottom: 4, + lineHeight: 22, + flex: 1, }, - categoryTag: { - paddingHorizontal: 8, - paddingVertical: 2, - borderRadius: 12, - alignSelf: 'flex-start', - }, - categoryText: { - color: '#FFFFFF', - fontSize: 12, - fontWeight: '500', + tagsContainer: { + flexDirection: 'row', + gap: 8, + marginBottom: 12, }, statusTag: { + flexDirection: 'row', + alignItems: 'center', + gap: 4, + paddingHorizontal: 8, + paddingVertical: 4, + borderRadius: 12, + backgroundColor: '#F3F4F6', + }, + statusTagText: { + fontSize: 12, + fontWeight: '500', + color: '#374151', + }, + priorityTag: { + flexDirection: 'row', + alignItems: 'center', + gap: 4, paddingHorizontal: 8, paddingVertical: 4, borderRadius: 12, }, - statusText: { + priorityTagText: { + fontSize: 12, + fontWeight: '500', color: '#FFFFFF', - fontSize: 12, - fontWeight: '500', - }, - description: { - fontSize: 14, - marginBottom: 12, - lineHeight: 20, - }, - progressContainer: { - marginBottom: 12, - }, - progressInfo: { - flexDirection: 'row', - justifyContent: 'space-between', - marginBottom: 6, - }, - progressText: { - fontSize: 12, - fontWeight: '500', }, progressBar: { - height: 6, - borderRadius: 3, + height: 2, + backgroundColor: '#E5E7EB', + borderRadius: 1, + marginBottom: 16, overflow: 'hidden', }, progressFill: { height: '100%', - borderRadius: 3, + borderRadius: 1, }, footer: { flexDirection: 'row', justifyContent: 'space-between', alignItems: 'center', }, - dateText: { - fontSize: 12, - fontWeight: '500', + teamSection: { + flexDirection: 'row', + alignItems: 'center', }, - actionButtons: { + avatars: { + flexDirection: 'row', + alignItems: 'center', + }, + avatar: { + width: 24, + height: 24, + borderRadius: 12, + alignItems: 'center', + justifyContent: 'center', + marginRight: -8, + borderWidth: 2, + borderColor: '#FFFFFF', + }, + avatarText: { + fontSize: 10, + fontWeight: '600', + color: '#FFFFFF', + }, + infoSection: { flexDirection: 'row', gap: 8, }, - actionButton: { - paddingHorizontal: 12, - paddingVertical: 6, - borderRadius: 16, - }, - skipButton: { + infoTag: { + flexDirection: 'row', + alignItems: 'center', + gap: 4, + paddingHorizontal: 8, + paddingVertical: 4, + borderRadius: 12, backgroundColor: '#F3F4F6', }, - skipButtonText: { - color: '#6B7280', - fontSize: 12, - fontWeight: '500', - }, - completeButton: { - backgroundColor: '#10B981', - }, - completeButtonText: { - color: '#FFFFFF', + infoTagText: { fontSize: 12, fontWeight: '500', + color: '#374151', }, }); diff --git a/components/TaskFilterTabs.tsx b/components/TaskFilterTabs.tsx new file mode 100644 index 0000000..1cb278f --- /dev/null +++ b/components/TaskFilterTabs.tsx @@ -0,0 +1,175 @@ +import React from 'react'; +import { StyleSheet, Text, TouchableOpacity, View } from 'react-native'; + +export type TaskFilterType = 'all' | 'pending' | 'completed'; + +interface TaskFilterTabsProps { + selectedFilter: TaskFilterType; + onFilterChange: (filter: TaskFilterType) => void; + taskCounts: { + all: number; + pending: number; + completed: number; + }; +} + +export const TaskFilterTabs: React.FC = ({ + selectedFilter, + onFilterChange, + taskCounts, +}) => { + return ( + + + {/* 全部 Tab */} + onFilterChange('all')} + > + + 全部 + + + + {taskCounts.all} + + + + + {/* 待完成 Tab */} + onFilterChange('pending')} + > + + 待完成 + + + + {taskCounts.pending} + + + + + {/* 已完成 Tab */} + onFilterChange('completed')} + > + + 已完成 + + + + {taskCounts.completed} + + + + + + ); +}; + +const styles = StyleSheet.create({ + container: { + paddingHorizontal: 20, + }, + tabContainer: { + backgroundColor: '#FFFFFF', + borderRadius: 24, + padding: 4, + flexDirection: 'row', + shadowColor: '#000', + shadowOffset: { width: 0, height: 1 }, + shadowOpacity: 0.05, + shadowRadius: 2, + elevation: 1, + borderWidth: 1, + borderColor: '#E5E7EB', + }, + tab: { + flex: 1, + flexDirection: 'row', + alignItems: 'center', + justifyContent: 'center', + paddingVertical: 10, + paddingHorizontal: 12, + borderRadius: 20, + gap: 6, + }, + activeTab: { + backgroundColor: '#7A5AF8', + shadowColor: '#7A5AF8', + shadowOffset: { width: 0, height: 2 }, + shadowOpacity: 0.2, + shadowRadius: 4, + elevation: 3, + }, + tabText: { + fontSize: 14, + fontWeight: '500', + color: '#374151', + }, + activeTabText: { + color: '#FFFFFF', + fontWeight: '600', + }, + badge: { + minWidth: 20, + height: 20, + borderRadius: 10, + alignItems: 'center', + justifyContent: 'center', + paddingHorizontal: 6, + }, + inactiveBadge: { + backgroundColor: '#E5E7EB', + }, + activeBadge: { + backgroundColor: '#EF4444', + }, + badgeText: { + fontSize: 12, + fontWeight: '600', + color: '#374151', + }, + activeBadgeText: { + color: '#FFFFFF', + }, +}); diff --git a/components/TaskProgressCard.tsx b/components/TaskProgressCard.tsx index 7f81399..647369d 100644 --- a/components/TaskProgressCard.tsx +++ b/components/TaskProgressCard.tsx @@ -1,140 +1,139 @@ import { TaskListItem } from '@/types/goals'; -import React from 'react'; +import MaterialIcons from '@expo/vector-icons/MaterialIcons'; +import React, { ReactNode } from 'react'; import { StyleSheet, Text, View } from 'react-native'; interface TaskProgressCardProps { tasks: TaskListItem[]; + headerButtons?: ReactNode; } export const TaskProgressCard: React.FC = ({ tasks, + headerButtons, }) => { - // 计算今日任务完成进度 - const todayTasks = tasks.filter(task => task.isToday); - const completedTodayTasks = todayTasks.filter(task => task.status === 'completed'); - const progressPercentage = todayTasks.length > 0 - ? Math.round((completedTodayTasks.length / todayTasks.length) * 100) - : 0; - - // 计算进度角度 - const progressAngle = (progressPercentage / 100) * 360; + // 计算各状态的任务数量 + const pendingTasks = tasks.filter(task => task.status === 'pending'); + const completedTasks = tasks.filter(task => task.status === 'completed'); + const skippedTasks = tasks.filter(task => task.status === 'skipped'); return ( - {/* 左侧内容 */} - - - 今日目标 - 加油,快完成啦! + {/* 标题区域 */} + + + 任务状态统计 + 各状态任务数量分布 - + {headerButtons && ( + + {headerButtons} + + )} - {/* 右侧进度圆环 */} - - {/* 背景圆环 */} - - - {/* 进度圆环 */} - - 0 ? '#8B5CF6' : 'transparent', - borderRightColor: progressAngle > 90 ? '#8B5CF6' : 'transparent', - borderBottomColor: progressAngle > 180 ? '#8B5CF6' : 'transparent', - borderLeftColor: progressAngle > 270 ? '#8B5CF6' : 'transparent', - transform: [{ rotate: '-90deg' }], - }, - ]} - /> + {/* 状态卡片区域 */} + + {/* 待完成 卡片 */} + + + + 待完成 + + {pendingTasks.length} - {/* 进度文字 */} - - {progressPercentage}% + {/* 已完成 卡片 */} + + + + 已完成 + + {completedTasks.length} + + + {/* 已跳过 卡片 */} + + + + 已跳过 + + {skippedTasks.length} - ); }; const styles = StyleSheet.create({ container: { - backgroundColor: '#8B5CF6', + backgroundColor: '#FFFFFF', borderRadius: 16, padding: 20, marginHorizontal: 20, marginBottom: 20, + shadowColor: '#000', + shadowOffset: { width: 0, height: 2 }, + shadowOpacity: 0.1, + shadowRadius: 8, + elevation: 4, + }, + header: { + marginBottom: 20, + flexDirection: 'row', + justifyContent: 'space-between', + alignItems: 'flex-start', + }, + titleContainer: { + flex: 1, + }, + headerButtons: { flexDirection: 'row', alignItems: 'center', - position: 'relative', - shadowColor: '#8B5CF6', - shadowOffset: { width: 0, height: 4 }, - shadowOpacity: 0.3, - shadowRadius: 8, - elevation: 8, - }, - leftContent: { - flex: 1, - marginRight: 20, - }, - textContainer: { - marginBottom: 16, + gap: 8, }, title: { - color: '#FFFFFF', - fontSize: 16, - fontWeight: '600', - marginBottom: 2, + fontSize: 20, + fontWeight: '700', + color: '#1F2937', + marginBottom: 4, }, subtitle: { - color: '#FFFFFF', fontSize: 14, + color: '#6B7280', fontWeight: '400', - opacity: 0.9, }, - progressContainer: { - width: 80, - height: 80, - justifyContent: 'center', + statusCards: { + flexDirection: 'row', + justifyContent: 'space-between', + gap: 12, + }, + statusCard: { + flex: 1, + backgroundColor: '#FFFFFF', + borderRadius: 12, + padding: 12, + borderWidth: 1, + borderColor: '#E5E7EB', + alignItems: 'flex-start', + minHeight: 80, + }, + cardHeader: { + flexDirection: 'row', alignItems: 'center', - position: 'relative', + marginBottom: 8, + gap: 6, + flexWrap: 'wrap', }, - progressCircle: { - position: 'absolute', - width: 80, - height: 80, - borderRadius: 40, + cardLabel: { + fontSize: 11, + fontWeight: '500', + color: '#1F2937', + lineHeight: 14, }, - progressBackground: { - borderWidth: 6, - borderColor: 'rgba(255, 255, 255, 0.3)', - }, - progressFill: { - borderWidth: 6, - borderColor: 'transparent', - justifyContent: 'center', - alignItems: 'center', - }, - progressArc: { - position: 'absolute', - }, - progressTextContainer: { - position: 'absolute', - justifyContent: 'center', - alignItems: 'center', - }, - progressText: { - color: '#FFFFFF', - fontSize: 16, + cardCount: { + fontSize: 24, fontWeight: '700', + color: '#1F2937', }, }); diff --git a/constants/Colors.ts b/constants/Colors.ts index 5b48891..37b61d3 100644 --- a/constants/Colors.ts +++ b/constants/Colors.ts @@ -6,8 +6,8 @@ // 原子调色板(与设计图一致) export const palette = { // Primary - primary: '#87CEEB', - ink: '#192126', + primary: '#7A5AF8', + ink: '#FFFFFF', // Secondary / Neutrals neutral100: '#888F92', @@ -18,7 +18,7 @@ export const palette = { purple: '#A48AED', red: '#ED4747', orange: '#FCC46F', - blue: '#87CEEB', // 更贴近logo背景的天空蓝 + blue: '#7A5AF8', // 更贴近logo背景的天空蓝 blueSecondary: '#4682B4', // 钢蓝色,用于选中状态 green: '#9ceb87', // 温暖的绿色,用于心情日历等 } as const;