import { Ionicons } from '@expo/vector-icons'; import dayjs from 'dayjs'; import * as Haptics from 'expo-haptics'; import { LinearGradient } from 'expo-linear-gradient'; import { useRouter } from 'expo-router'; import React, { useEffect, useState } from 'react'; import { Alert, FlatList, SafeAreaView, StyleSheet, Text, TextInput, TouchableOpacity, View } from 'react-native'; import Animated, { FadeInUp } from 'react-native-reanimated'; import { ThemedText } from '@/components/ThemedText'; import { HeaderBar } from '@/components/ui/HeaderBar'; import { palette } from '@/constants/Colors'; import { useAppDispatch, useAppSelector } from '@/hooks/redux'; import { loadPlans } from '@/store/trainingPlanSlice'; import { createWorkoutSession } from '@/store/workoutSlice'; const GOAL_TEXT: Record = { postpartum_recovery: { title: '产后恢复', color: '#9BE370', description: '温和激活,核心重建' }, fat_loss: { title: '减脂塑形', color: '#FFB86B', description: '全身燃脂,线条雕刻' }, posture_correction: { title: '体态矫正', color: '#95CCE3', description: '打开胸肩,改善圆肩驼背' }, core_strength: { title: '核心力量', color: '#A48AED', description: '核心稳定,提升运动表现' }, flexibility: { title: '柔韧灵活', color: '#B0F2A7', description: '拉伸延展,释放紧张' }, rehab: { title: '康复保健', color: '#FF8E9E', description: '循序渐进,科学修复' }, stress_relief: { title: '释压放松', color: '#9BD1FF', description: '舒缓身心,改善睡眠' }, }; // 动态背景组件 function DynamicBackground({ color }: { color: string }) { return ( ); } export default function CreateWorkoutSessionScreen() { const router = useRouter(); const dispatch = useAppDispatch(); const { plans, loading: plansLoading } = useAppSelector((s) => s.trainingPlan); const [sessionName, setSessionName] = useState(''); const [selectedPlanId, setSelectedPlanId] = useState(null); const [creating, setCreating] = useState(false); useEffect(() => { dispatch(loadPlans()); }, [dispatch]); // 自动生成会话名称 useEffect(() => { if (!sessionName) { const today = new Date(); const dateStr = `${today.getMonth() + 1}月${today.getDate()}日`; setSessionName(`${dateStr}训练`); } }, [sessionName]); const selectedPlan = plans.find(p => p.id === selectedPlanId); const goalConfig = selectedPlan?.goal ? (GOAL_TEXT[selectedPlan.goal] || { title: '训练', color: palette.primary, description: '开始你的训练之旅' }) : { title: '新建训练', color: palette.primary, description: '选择创建方式' }; // 创建自定义会话 const handleCreateCustomSession = async () => { if (creating || !sessionName.trim()) return; setCreating(true); try { await dispatch(createWorkoutSession({ name: sessionName.trim(), scheduledDate: dayjs().format('YYYY-MM-DD') })).unwrap(); // 创建成功后跳转到选择动作页面 router.replace('/training-plan/schedule/select' as any); } catch (error) { console.error('创建训练会话失败:', error); Alert.alert('创建失败', '创建训练会话时出现错误,请稍后重试'); } finally { setCreating(false); } }; // 从训练计划创建会话 const handleCreateFromPlan = async () => { if (creating || !selectedPlan || !sessionName.trim()) return; setCreating(true); try { await dispatch(createWorkoutSession({ name: sessionName.trim(), trainingPlanId: selectedPlan.id, scheduledDate: dayjs().format('YYYY-MM-DD') })).unwrap(); // 创建成功后返回到训练记录页面 router.back(); } catch (error) { console.error('创建训练会话失败:', error); Alert.alert('创建失败', '创建训练会话时出现错误,请稍后重试'); } finally { setCreating(false); } }; // 渲染训练计划卡片 const renderPlanItem = ({ item, index }: { item: any; index: number }) => { const isSelected = item.id === selectedPlanId; const planGoalConfig = GOAL_TEXT[item.goal] || { title: '训练计划', color: palette.primary, description: '开始你的训练之旅' }; return ( { setSelectedPlanId(isSelected ? null : item.id); Haptics.impactAsync(Haptics.ImpactFeedbackStyle.Light); }} activeOpacity={0.9} > {item.name} {planGoalConfig.title} {planGoalConfig.description} {isSelected ? ( ) : ( )} {item.exercises && item.exercises.length > 0 && ( {item.exercises.length} 个动作 )} ); }; return ( {/* 动态背景 */} router.back()} withSafeTop={false} transparent={true} tone="light" /> {/* 会话信息设置 */} 训练会话设置 {goalConfig.description} {/* 会话名称输入 */} 会话名称 {/* 创建方式选择 */} 选择创建方式 {/* 自定义会话 */} 自定义会话 创建空的训练会话,然后手动添加动作 {/* 从训练计划导入 */} 从训练计划导入 选择一个训练计划,将其动作导入到新会话中 {plansLoading ? ( 加载训练计划中... ) : plans.length === 0 ? ( 暂无训练计划 router.push('/training-plan/create' as any)} > 创建训练计划 ) : ( <> item.id} renderItem={renderPlanItem} contentContainerStyle={styles.plansList} showsVerticalScrollIndicator={false} scrollEnabled={false} /> {selectedPlan && ( {creating ? '创建中...' : `从 "${selectedPlan.name}" 创建会话`} )} )} ); } const styles = StyleSheet.create({ safeArea: { flex: 1, }, contentWrapper: { flex: 1, }, content: { flex: 1, paddingHorizontal: 20, }, // 动态背景 backgroundOrb: { position: 'absolute', width: 300, height: 300, borderRadius: 150, top: -150, right: -100, }, backgroundOrb2: { position: 'absolute', width: 400, height: 400, borderRadius: 200, bottom: -200, left: -150, }, // 会话信息头部 sessionHeader: { flexDirection: 'row', alignItems: 'center', padding: 16, borderRadius: 16, marginBottom: 20, }, sessionColorIndicator: { width: 4, height: 40, borderRadius: 2, marginRight: 12, }, sessionInfo: { flex: 1, }, sessionTitle: { fontSize: 18, fontWeight: '800', color: '#192126', marginBottom: 4, }, sessionDescription: { fontSize: 13, color: '#5E6468', opacity: 0.8, }, // 输入区域 inputSection: { marginBottom: 24, }, inputLabel: { fontSize: 14, fontWeight: '700', color: '#192126', marginBottom: 8, }, textInput: { backgroundColor: '#FFFFFF', borderRadius: 12, paddingHorizontal: 16, paddingVertical: 12, fontSize: 16, color: '#192126', borderWidth: 1, shadowColor: '#000', shadowOpacity: 0.06, shadowRadius: 8, shadowOffset: { width: 0, height: 2 }, elevation: 2, }, // 创建方式区域 methodSection: { flex: 1, }, sectionTitle: { fontSize: 16, fontWeight: '800', color: '#192126', marginBottom: 16, }, // 方式卡片 methodCard: { backgroundColor: '#FFFFFF', borderRadius: 16, padding: 16, marginBottom: 16, flexDirection: 'row', alignItems: 'center', borderWidth: 1, shadowColor: '#000', shadowOpacity: 0.06, shadowRadius: 8, shadowOffset: { width: 0, height: 2 }, elevation: 2, }, methodIcon: { marginRight: 12, }, methodInfo: { flex: 1, }, methodTitle: { fontSize: 16, fontWeight: '700', color: '#192126', marginBottom: 4, }, methodDescription: { fontSize: 12, color: '#6B7280', lineHeight: 16, }, // 训练计划导入区域 planImportSection: { marginTop: 8, }, // 训练计划列表 plansList: { marginTop: 16, marginBottom: 20, }, planCard: { backgroundColor: '#FFFFFF', borderRadius: 16, marginBottom: 12, borderLeftWidth: 4, shadowColor: '#000', shadowOpacity: 0.06, shadowRadius: 8, shadowOffset: { width: 0, height: 2 }, elevation: 2, }, planCardContent: { padding: 16, }, planHeader: { flexDirection: 'row', justifyContent: 'space-between', alignItems: 'flex-start', marginBottom: 8, }, planInfo: { flex: 1, }, planName: { fontSize: 16, fontWeight: '800', color: '#192126', marginBottom: 4, }, planGoal: { fontSize: 12, fontWeight: '700', marginBottom: 2, }, planStatus: { marginLeft: 12, }, radioButton: { width: 24, height: 24, borderRadius: 12, borderWidth: 2, }, planStats: { marginTop: 8, }, statsText: { fontSize: 12, color: '#6B7280', }, // 空状态 loadingContainer: { alignItems: 'center', paddingVertical: 24, }, loadingText: { fontSize: 14, color: '#6B7280', }, emptyPlansContainer: { alignItems: 'center', paddingVertical: 32, }, emptyPlansText: { fontSize: 14, color: '#6B7280', marginTop: 8, marginBottom: 16, }, createPlanBtn: { paddingVertical: 10, paddingHorizontal: 20, borderRadius: 8, }, createPlanBtnText: { color: '#FFFFFF', fontSize: 14, fontWeight: '700', }, // 确认按钮 confirmBtn: { paddingVertical: 16, borderRadius: 12, alignItems: 'center', marginTop: 10, }, confirmBtnText: { color: '#FFFFFF', fontWeight: '800', fontSize: 16, }, });