import { useGlobalDialog } from '@/components/ui/DialogProvider'; import { Colors } from '@/constants/Colors'; import { useAppDispatch } from '@/hooks/redux'; import { useColorScheme } from '@/hooks/useColorScheme'; import { completeTask, skipTask } from '@/store/tasksSlice'; import { TaskListItem } from '@/types/goals'; import { useRouter } from 'expo-router'; import React from 'react'; import { Alert, Animated, Image, StyleSheet, Text, TouchableOpacity, View } from 'react-native'; interface TaskCardProps { task: TaskListItem; onTaskCompleted?: (task: TaskListItem) => void; // 任务完成回调 } export const TaskCard: React.FC = ({ task, onTaskCompleted, }) => { const theme = useColorScheme() ?? 'light'; const colorTokens = Colors[theme]; const dispatch = useAppDispatch(); const { showConfirm } = useGlobalDialog(); const router = useRouter(); // 创建进度条动画值 const progressAnimation = React.useRef(new Animated.Value(0)).current; // 当任务进度变化时,启动动画 React.useEffect(() => { const targetProgress = task.progressPercentage > 0 ? Math.min(task.progressPercentage, 100) : 6; Animated.timing(progressAnimation, { toValue: targetProgress, duration: 800, // 动画持续时间800毫秒 useNativeDriver: false, // 因为我们要动画width属性,所以不能使用原生驱动 }).start(); }, [task.progressPercentage, progressAnimation]); const getStatusText = (status: string) => { switch (status) { case 'completed': return '已完成'; case 'in_progress': return '进行中'; case 'overdue': return '已过期'; case 'skipped': return '已跳过'; default: return '待开始'; } }; 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 month = date.toLocaleDateString('zh-CN', { month: 'short' }); const day = date.getDate(); return `${day} ${month}`; }; const handleCompleteTask = async () => { // 如果任务已经完成,不执行任何操作 if (task.status === 'completed') { return; } try { // 调用完成任务 API await dispatch(completeTask({ taskId: task.id, completionData: { count: 1, notes: '通过任务卡片完成' } })).unwrap(); // 触发任务完成回调 onTaskCompleted?.(task); } catch (error) { Alert.alert('错误', '完成任务失败,请重试'); } }; const handleSkipTask = async () => { // 如果任务已经完成或已跳过,不执行任何操作 if (task.status === 'completed' || task.status === 'skipped') { return; } // 显示确认弹窗 showConfirm( { title: '确认跳过任务', message: `确定要跳过任务"${task.title}"吗?\n\n跳过后的任务将不会显示在任务列表中,且无法恢复。`, confirmText: '跳过', cancelText: '取消', destructive: true, icon: 'warning', iconColor: '#F59E0B', }, async () => { try { // 调用跳过任务 API await dispatch(skipTask({ taskId: task.id, skipData: { reason: '用户主动跳过' } })).unwrap(); } catch (error) { Alert.alert('错误', '跳过任务失败,请重试'); } } ); }; const handleTaskPress = () => { router.push(`/task-detail?taskId=${task.id}`); }; const renderActionIcons = () => { if (task.status === 'completed' || task.status === 'overdue' || task.status === 'skipped') { return null; } return ( {/* 完成任务图标 */} {/* 跳过任务图标 - 仅对进行中的任务显示 */} {task.status === 'pending' && ( )} ); }; return ( {/* 左侧图标区域 */} {/* 右侧信息区域 */} {/* 任务标题 */} {task.title} {/* 进度条 */} {/* 背景进度条 */} {/* 实际进度条 */} 0 ? '#8B5CF6' : '#C7D2FE', // 浅紫色,表示待开始 }, ]} /> {/* 进度文字 */} 20 || task.status === 'completed' ? '#FFFFFF' : '#374151', // 进度较少时使用深色文字 } ]}> {task.currentCount}/{task.targetCount} 次 {/* 操作按钮 */} {renderActionIcons()} ); }; const styles = StyleSheet.create({ container: { padding: 14, borderRadius: 30, marginBottom: 12, shadowColor: '#000', shadowOffset: { width: 0, height: 2 }, shadowOpacity: 0.1, shadowRadius: 4, elevation: 3, }, cardContent: { flexDirection: 'row', alignItems: 'center', gap: 10, }, iconSection: { flexShrink: 0, }, iconCircle: { width: 36, height: 36, borderRadius: 18, backgroundColor: '#F3E8FF', // 浅紫色背景 alignItems: 'center', justifyContent: 'center', }, infoSection: { flex: 1, gap: 8, }, title: { fontSize: 15, fontWeight: '600', lineHeight: 20, color: '#1F2937', // 深蓝紫色文字 marginBottom: 2, }, progressContainer: { position: 'relative', height: 14, justifyContent: 'center', marginTop: 4, }, progressBackground: { position: 'absolute', left: 0, right: 0, height: 14, backgroundColor: '#F3F4F6', borderRadius: 10, }, progressBar: { height: 14, borderRadius: 10, position: 'absolute', left: 0, minWidth: '6%', // 确保最小宽度可见 }, progressText: { fontSize: 12, fontWeight: '600', color: '#FFFFFF', textAlign: 'center', position: 'absolute', left: 0, right: 0, zIndex: 1, }, actionIconsContainer: { flexDirection: 'row', alignItems: 'center', gap: 6, flexShrink: 0, }, iconContainer: { width: 28, height: 28, borderRadius: 14, alignItems: 'center', justifyContent: 'center', backgroundColor: '#F3F4F6', }, skipIconContainer: { width: 28, height: 28, borderRadius: 14, backgroundColor: '#F3F4F6', alignItems: 'center', justifyContent: 'center', }, taskIcon: { width: 18, height: 18, }, // 保留其他样式以备后用 header: { marginBottom: 12, }, titleSection: { flexDirection: 'row', alignItems: 'center', gap: 12, }, 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, }, priorityTagText: { fontSize: 12, fontWeight: '500', color: '#FFFFFF', }, progressBarOld: { height: 6, backgroundColor: '#F3F4F6', borderRadius: 3, marginBottom: 16, overflow: 'visible', shadowColor: '#000', shadowOffset: { width: 0, height: 1 }, shadowOpacity: 0.1, shadowRadius: 2, elevation: 2, position: 'relative', }, progressFill: { height: '100%', borderRadius: 3, shadowColor: '#000', shadowOffset: { width: 0, height: 1 }, shadowOpacity: 0.2, shadowRadius: 2, elevation: 3, }, progressGlow: { position: 'absolute', right: 0, top: 0, width: 8, height: '100%', backgroundColor: 'rgba(255, 255, 255, 0.6)', borderRadius: 3, }, progressTextContainer: { position: 'absolute', right: 0, top: -6, backgroundColor: '#FFFFFF', paddingHorizontal: 6, paddingVertical: 2, borderRadius: 8, shadowColor: '#000', shadowOffset: { width: 0, height: 1 }, shadowOpacity: 0.1, shadowRadius: 2, elevation: 2, borderWidth: 1, borderColor: '#E5E7EB', zIndex: 1, }, footer: { flexDirection: 'row', justifyContent: 'space-between', alignItems: 'center', }, teamSection: { flexDirection: 'row', alignItems: 'center', }, avatars: { flexDirection: 'row', alignItems: 'center', }, avatar: { width: 24, height: 24, borderRadius: 24, marginRight: -8, borderWidth: 2, borderColor: '#FFFFFF', overflow: 'hidden', }, avatarImage: { width: '100%', height: '100%', }, infoTag: { flexDirection: 'row', alignItems: 'center', gap: 4, paddingHorizontal: 8, paddingVertical: 4, borderRadius: 12, }, infoTagText: { fontSize: 12, fontWeight: '500', color: '#374151', }, });