import { useGlobalDialog } from '@/components/ui/DialogProvider'; import { HeaderBar } from '@/components/ui/HeaderBar'; import { Colors } from '@/constants/Colors'; import { useAppDispatch, useAppSelector } from '@/hooks/redux'; import { useColorScheme } from '@/hooks/useColorScheme'; import { completeTask, skipTask } from '@/store/tasksSlice'; import MaterialIcons from '@expo/vector-icons/MaterialIcons'; import { useLocalSearchParams, useRouter } from 'expo-router'; import React, { useState } from 'react'; import { Alert, Image, ScrollView, StyleSheet, Text, TextInput, TouchableOpacity, View } from 'react-native'; export default function TaskDetailScreen() { const { taskId } = useLocalSearchParams<{ taskId: string }>(); const router = useRouter(); const theme = useColorScheme() ?? 'light'; const colorTokens = Colors[theme]; const dispatch = useAppDispatch(); const { showConfirm } = useGlobalDialog(); // 从Redux中获取任务数据 const { tasks, tasksLoading } = useAppSelector(state => state.tasks); const task = tasks.find(t => t.id === taskId) || null; const [comment, setComment] = useState(''); const getStatusText = (status: string) => { switch (status) { case 'completed': return '已完成'; case 'in_progress': return '进行中'; case 'overdue': return '已过期'; case 'skipped': return '已跳过'; default: return '待开始'; } }; const getStatusColor = (status: string) => { switch (status) { case 'completed': return '#10B981'; case 'in_progress': return '#7A5AF8'; case 'overdue': return '#EF4444'; case 'skipped': return '#6B7280'; default: return '#6B7280'; } }; const getDifficultyText = (difficulty: string) => { switch (difficulty) { case 'very_easy': return '非常简单 (少于一天)'; case 'easy': return '简单 (1-2天)'; case 'medium': return '中等 (3-5天)'; case 'hard': return '困难 (1-2周)'; case 'very_hard': return '非常困难 (2周以上)'; default: return '非常简单 (少于一天)'; } }; const getDifficultyColor = (difficulty: string) => { switch (difficulty) { case 'very_easy': return '#10B981'; case 'easy': return '#34D399'; case 'medium': return '#F59E0B'; case 'hard': return '#F97316'; case 'very_hard': return '#EF4444'; default: return '#10B981'; } }; const formatDate = (dateString: string) => { const date = new Date(dateString); const options: Intl.DateTimeFormatOptions = { year: 'numeric', month: 'long', day: 'numeric' }; return `创建于 ${date.toLocaleDateString('zh-CN', options)}`; }; const handleCompleteTask = async () => { if (!task || task.status === 'completed') { return; } try { await dispatch(completeTask({ taskId: task.id, completionData: { count: 1, notes: '通过任务详情页面完成' } })).unwrap(); // 检查任务是否真正完成(当前完成次数是否达到目标次数) const updatedTask = tasks.find(t => t.id === task.id); if (updatedTask && updatedTask.currentCount >= updatedTask.targetCount) { Alert.alert('成功', '任务已完成!'); router.back(); } else { Alert.alert('成功', '任务进度已更新!'); } } catch (error) { Alert.alert('错误', '完成任务失败,请重试'); } }; const handleSkipTask = async () => { if (!task || task.status === 'completed' || task.status === 'skipped') { return; } showConfirm( { title: '确认跳过任务', message: `确定要跳过任务"${task.title}"吗?\n\n跳过后的任务将不会显示在任务列表中,且无法恢复。`, confirmText: '跳过', cancelText: '取消', destructive: true, icon: 'warning', iconColor: '#F59E0B', }, async () => { try { await dispatch(skipTask({ taskId: task.id, skipData: { reason: '用户主动跳过' } })).unwrap(); Alert.alert('成功', '任务已跳过!'); router.back(); } catch (error) { Alert.alert('错误', '跳过任务失败,请重试'); } } ); }; const handleSendComment = () => { if (comment.trim()) { // 这里应该调用API发送评论 console.log('发送评论:', comment); setComment(''); Alert.alert('成功', '评论已发送!'); } }; if (tasksLoading) { return ( router.back()} /> 加载中... ); } if (!task) { return ( router.back()} /> 任务不存在 ); } return ( {/* 使用HeaderBar组件 */} router.back()} right={ task.status !== 'completed' && task.status !== 'skipped' && task.currentCount < task.targetCount ? ( ) : undefined } /> {/* 任务标题和创建时间 */} {task.title} {formatDate(task.startDate)} {/* 状态标签 */} {getStatusText(task.status)} {/* 描述区域 */} 描述 {task.description || '暂无描述'} {/* 优先级和难度 */} 优先级 难度 非常简单 (少于一天) {/* 任务进度信息 */} 进度 {/* 进度条 */} 0 ? `${Math.min(task.progressPercentage, 100)}%` : '2%', backgroundColor: task.progressPercentage >= 100 ? '#10B981' : task.progressPercentage >= 50 ? '#F59E0B' : task.progressPercentage > 0 ? colorTokens.primary : '#E5E7EB', }, ]} /> {task.progressPercentage > 0 && task.progressPercentage < 100 && ( )} {/* 进度文本 */} {task.currentCount}/{task.targetCount} {/* 进度详细信息 */} 目标次数 {task.targetCount} 已完成 {task.currentCount} 剩余天数 {task.daysRemaining} {/* 评论区域 */} 评论区域 {/* 底部操作按钮 */} {task.status !== 'completed' && task.status !== 'skipped' && task.currentCount < task.targetCount && ( 跳过任务 )} ); } const styles = StyleSheet.create({ container: { flex: 1, }, loadingContainer: { flex: 1, justifyContent: 'center', alignItems: 'center', }, loadingText: { fontSize: 16, fontWeight: '500', }, errorContainer: { flex: 1, justifyContent: 'center', alignItems: 'center', }, errorText: { fontSize: 16, fontWeight: '500', }, completeButton: { width: 32, height: 32, borderRadius: 16, backgroundColor: '#7A5AF8', alignItems: 'center', justifyContent: 'center', }, taskIcon: { width: 20, height: 20, }, scrollView: { flex: 1, }, titleSection: { padding: 16, paddingBottom: 8, }, taskTitle: { fontSize: 20, fontWeight: '600', lineHeight: 28, marginBottom: 4, }, createdDate: { fontSize: 14, fontWeight: '400', opacity: 0.7, }, statusContainer: { paddingHorizontal: 16, paddingBottom: 16, alignItems: 'flex-end', }, statusTag: { alignSelf: 'flex-end', paddingHorizontal: 12, paddingVertical: 6, borderRadius: 16, }, statusTagText: { fontSize: 14, fontWeight: '600', color: '#FFFFFF', }, imagePlaceholder: { height: 240, backgroundColor: '#F9FAFB', marginHorizontal: 16, marginBottom: 20, borderRadius: 12, borderWidth: 2, borderColor: '#E5E7EB', borderStyle: 'dashed', alignItems: 'center', justifyContent: 'center', }, imagePlaceholderText: { fontSize: 16, fontWeight: '500', color: '#9CA3AF', marginTop: 8, }, descriptionSection: { paddingHorizontal: 16, marginBottom: 20, }, sectionTitle: { fontSize: 16, fontWeight: '600', marginBottom: 12, }, descriptionText: { fontSize: 15, lineHeight: 22, fontWeight: '400', }, infoSection: { paddingHorizontal: 16, marginBottom: 20, }, infoItem: { flexDirection: 'row', alignItems: 'center', justifyContent: 'space-between', marginBottom: 12, }, infoLabel: { fontSize: 15, fontWeight: '500', }, priorityTag: { flexDirection: 'row', alignItems: 'center', gap: 4, paddingHorizontal: 10, paddingVertical: 4, borderRadius: 12, backgroundColor: '#EF4444', }, priorityTagText: { fontSize: 13, fontWeight: '600', color: '#FFFFFF', }, difficultyTag: { flexDirection: 'row', alignItems: 'center', gap: 4, paddingHorizontal: 10, paddingVertical: 4, borderRadius: 12, }, difficultyTagText: { fontSize: 13, fontWeight: '600', color: '#FFFFFF', }, progressSection: { paddingHorizontal: 16, marginBottom: 20, }, progressBar: { 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, }, progressText: { fontSize: 10, fontWeight: '600', color: '#374151', }, progressInfo: { flexDirection: 'row', justifyContent: 'space-between', }, progressItem: { alignItems: 'center', flex: 1, }, progressLabel: { fontSize: 13, fontWeight: '400', marginBottom: 4, }, progressValue: { fontSize: 18, fontWeight: '600', }, commentSection: { paddingHorizontal: 16, marginBottom: 20, }, commentInputContainer: { flexDirection: 'row', alignItems: 'center', gap: 12, }, commentAvatar: { width: 28, height: 28, borderRadius: 14, overflow: 'hidden', }, commentAvatarImage: { width: '100%', height: '100%', }, commentInputWrapper: { flex: 1, flexDirection: 'row', alignItems: 'center', gap: 8, }, commentInput: { flex: 1, minHeight: 36, maxHeight: 120, paddingHorizontal: 12, paddingVertical: 8, borderRadius: 18, fontSize: 15, textAlignVertical: 'top', }, sendButton: { width: 28, height: 28, borderRadius: 14, alignItems: 'center', justifyContent: 'center', }, actionButtons: { paddingHorizontal: 16, paddingBottom: 20, }, actionButton: { flexDirection: 'row', alignItems: 'center', justifyContent: 'center', gap: 8, paddingVertical: 12, paddingHorizontal: 16, borderRadius: 8, borderWidth: 1, }, skipButton: { backgroundColor: '#F9FAFB', borderColor: '#E5E7EB', }, skipButtonText: { fontSize: 16, fontWeight: '500', color: '#6B7280', }, });