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',
},
});