import { Ionicons } from '@expo/vector-icons'; import MaskedView from '@react-native-masked-view/masked-view'; import { LinearGradient } from 'expo-linear-gradient'; import { useLocalSearchParams, useRouter } from 'expo-router'; import React, { useEffect, useMemo, useState } from 'react'; import { Alert, FlatList, Modal, Pressable, SafeAreaView, ScrollView, StyleSheet, Switch, Text, TextInput, TouchableOpacity, View } from 'react-native'; import Animated, { FadeInUp, FadeOut, interpolate, Layout, useAnimatedStyle, useSharedValue, withRepeat, withSpring, withTiming } from 'react-native-reanimated'; import { ThemedText } from '@/components/ThemedText'; import { HeaderBar } from '@/components/ui/HeaderBar'; import { Colors, palette } from '@/constants/Colors'; import { useAppDispatch, useAppSelector } from '@/hooks/redux'; import { useColorScheme } from '@/hooks/useColorScheme'; import { activatePlan, clearError, deletePlan, loadPlans, type TrainingPlan } from '@/store/trainingPlanSlice'; import { buildClassicalSession } from '@/utils/classicalSession'; // 训练计划排课项目类型 export interface ScheduleExercise { key: string; name: string; category: string; sets: number; reps?: number; durationSec?: number; restSec?: number; note?: string; itemType?: 'exercise' | 'rest' | 'note'; completed?: boolean; } // 训练计划排课数据 export interface PlanSchedule { planId: string; exercises: ScheduleExercise[]; note?: string; lastModified: string; } // Tab 类型定义 type TabType = 'list' | 'schedule'; 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() { const rotate = useSharedValue(0); const scale = useSharedValue(1); React.useEffect(() => { rotate.value = withRepeat(withTiming(360, { duration: 20000 }), -1); scale.value = withRepeat(withTiming(1.2, { duration: 8000 }), -1, true); }, []); const backgroundStyle = useAnimatedStyle(() => ({ transform: [ { rotate: `${rotate.value}deg` }, { scale: scale.value } ], })); return ( ); } // 渐变文字 function GradientText({ children }: { children: string }) { return ( {children}}> {children} ); } // 新视觉训练计划卡片 function PlanCard({ plan, onPress, onDelete, onActivate, onSchedule, isActive, index }: { plan: TrainingPlan; onPress: () => void; onDelete: () => void; onActivate: () => void; onSchedule: () => void; isActive?: boolean; index: number }) { const scale = useSharedValue(1); const glow = useSharedValue(0); React.useEffect(() => { glow.value = withRepeat(withTiming(1, { duration: 2000 + index * 100 }), -1, true); }, [index]); const goalConfig = GOAL_TEXT[plan.goal] || { title: '训练计划', color: palette.primary, description: '开始你的训练之旅' }; const cardStyle = useAnimatedStyle(() => ({ transform: [{ scale: scale.value }], })); const glowStyle = useAnimatedStyle(() => { const opacity = isActive ? interpolate(glow.value, [0, 1], [0.25, 0.55]) : interpolate(glow.value, [0, 1], [0.1, 0.3]); return { shadowOpacity: opacity, shadowColor: '#000', shadowRadius: isActive ? 28 : 18, elevation: isActive ? 18 : 10, borderColor: isActive ? `${goalConfig.color}55` : '#1B262B', }; }); const formatDate = (dateStr: string) => { const date = new Date(dateStr); return `${date.getMonth() + 1}月${date.getDate()}日`; }; const getFrequencyText = () => { if (plan.mode === 'daysOfWeek') { return `每周${plan.daysOfWeek.length}天`; } return `每周${plan.sessionsPerWeek}次`; }; const displayTitle = plan.name?.trim() ? plan.name : goalConfig.title; const frequencyCount = plan.mode === 'daysOfWeek' ? plan.daysOfWeek.length : plan.sessionsPerWeek; const sinceCreatedDays = Math.max(0, Math.floor((Date.now() - new Date(plan.createdAt).getTime()) / (24 * 3600 * 1000))); const startDeltaDays = Math.floor((Date.now() - new Date(plan.startDate).getTime()) / (24 * 3600 * 1000)); return ( { Alert.alert('操作', '选择要执行的操作', [ { text: '排课', onPress: onSchedule }, { text: isActive ? '已激活' : '激活', onPress: onActivate }, { text: '删除', style: 'destructive', onPress: onDelete }, { text: '取消', style: 'cancel' }, ]); }} onPressIn={() => { scale.value = withSpring(0.98); }} onPressOut={() => { scale.value = withSpring(1); }} style={styles.darkCard} > {displayTitle} {`${goalConfig.description} · 开始于 ${formatDate(plan.startDate)} · ${getFrequencyText()}${plan.preferredTimeOfDay ? ` · ${plan.preferredTimeOfDay === 'morning' ? '晨练' : plan.preferredTimeOfDay === 'noon' ? '午间' : '晚间'}` : ''}`} 排课 {isActive ? '已激活' : '激活'} { Alert.alert('确认删除', '确定要删除这个训练计划吗?此操作无法撤销。', [ { text: '取消', style: 'cancel' }, { text: '删除', style: 'destructive', onPress: onDelete }, ]); }} hitSlop={8}> 删除 ); } // 底部 Tab 组件 function BottomTabs({ activeTab, onTabChange, selectedPlan }: { activeTab: TabType; onTabChange: (tab: TabType) => void; selectedPlan?: TrainingPlan; }) { const theme = useColorScheme() ?? 'light'; const colorTokens = Colors[theme]; return ( onTabChange('list')} > {activeTab === 'list' && ( 训练计划 )} onTabChange('schedule')} > {activeTab === 'schedule' && ( 锻炼排期 )} ); } export default function TrainingPlanScreen() { const router = useRouter(); const dispatch = useAppDispatch(); const params = useLocalSearchParams<{ planId?: string; newExercise?: string }>(); const { plans, currentId, loading, error } = useAppSelector((s) => s.trainingPlan); // Tab 状态管理 const [activeTab, setActiveTab] = useState('list'); const [selectedPlanId, setSelectedPlanId] = useState(params.planId || currentId || null); // 排课相关状态 const [exercises, setExercises] = useState([]); const [scheduleNote, setScheduleNote] = useState(''); const [hasUnsavedChanges, setHasUnsavedChanges] = useState(false); // 一键排课配置 const [genVisible, setGenVisible] = useState(false); const [genLevel, setGenLevel] = useState<'beginner' | 'intermediate' | 'advanced'>('beginner'); const [genWithRests, setGenWithRests] = useState(true); const [genWithNotes, setGenWithNotes] = useState(true); const [genRest, setGenRest] = useState('30'); const selectedPlan = useMemo(() => plans.find(p => p.id === selectedPlanId), [plans, selectedPlanId]); // 模拟加载排课数据的函数 const loadScheduleData = async (planId: string): Promise => { // 模拟 API 调用延迟 await new Promise(resolve => setTimeout(resolve, 300)); // 模拟数据 - 在实际应用中,这里应该从后端或本地存储获取数据 const mockData: Record = { // 示例数据结构,实际应用中应从服务器或本地存储获取 // 'plan1': { // planId: 'plan1', // exercises: [...], // note: '示例备注', // lastModified: new Date().toISOString() // } }; return mockData[planId] || null; }; // 监听 selectedPlan 变化,加载对应的排课数据 useEffect(() => { const loadSchedule = async () => { if (selectedPlan) { try { const scheduleData = await loadScheduleData(selectedPlan.id); if (scheduleData) { setExercises(scheduleData.exercises); setScheduleNote(scheduleData.note || ''); } else { // 如果没有保存的排课数据,重置为默认空状态 setExercises([]); setScheduleNote(''); } } catch (error) { console.error('加载排课数据失败:', error); // 出错时重置为默认空状态 setExercises([]); setScheduleNote(''); } } else { // 没有选中计划时,重置为默认空状态 setExercises([]); setScheduleNote(''); } }; loadSchedule(); }, [selectedPlan]); useEffect(() => { dispatch(loadPlans()); }, [dispatch]); useEffect(() => { if (error) { console.error('训练计划错误:', error); const timer = setTimeout(() => { dispatch(clearError()); }, 3000); return () => clearTimeout(timer); } }, [error, dispatch]); // 处理从选择页面传回的新动作 useEffect(() => { if (params.newExercise) { try { const newExercise: ScheduleExercise = JSON.parse(params.newExercise); setExercises(prev => [...prev, newExercise]); setHasUnsavedChanges(true); router.setParams({ newExercise: undefined } as any); } catch (error) { console.error('解析新动作数据失败:', error); } } }, [params.newExercise]); const handleActivate = async (planId: string) => { try { await dispatch(activatePlan(planId)); } catch (error) { console.error('激活训练计划失败:', error); } } const handlePlanSelect = (plan: TrainingPlan) => { setSelectedPlanId(plan.id); setActiveTab('schedule'); // TODO: 加载该计划的排课数据 } const handleTabChange = (tab: TabType) => { if (tab === 'schedule' && !selectedPlanId && plans.length > 0) { // 如果没有选中计划但要切换到排课页面,自动选择当前激活的计划或第一个计划 const targetPlan = plans.find(p => p.id === currentId) || plans[0]; setSelectedPlanId(targetPlan.id); } setActiveTab(tab); } // 排课相关方法 const handleSave = async () => { if (!selectedPlan) return; try { const scheduleData: PlanSchedule = { planId: selectedPlan.id, exercises, note: scheduleNote, lastModified: new Date().toISOString(), }; console.log('保存排课数据:', scheduleData); setHasUnsavedChanges(false); Alert.alert('保存成功', '训练计划排课已保存'); } catch (error) { console.error('保存排课失败:', error); Alert.alert('保存失败', '请稍后重试'); } }; const handleAddExercise = () => { router.push(`/training-plan/schedule/select?planId=${selectedPlanId}` as any); }; const handleRemoveExercise = (key: string) => { Alert.alert('确认移除', '确定要移除该动作吗?', [ { text: '取消', style: 'cancel' }, { text: '移除', style: 'destructive', onPress: () => { setExercises(prev => prev.filter(ex => ex.key !== key)); setHasUnsavedChanges(true); }, }, ]); }; const handleToggleCompleted = (key: string) => { setExercises(prev => prev.map(ex => ex.key === key ? { ...ex, completed: !ex.completed } : ex )); setHasUnsavedChanges(true); }; const onGenerate = () => { const restSec = Math.max(10, Math.min(120, parseInt(genRest || '30', 10))); const { items, note } = buildClassicalSession({ withSectionRests: genWithRests, restSeconds: restSec, withNotes: genWithNotes, level: genLevel }); const scheduleItems: ScheduleExercise[] = items.map((item, index) => ({ key: `generated_${Date.now()}_${index}`, name: item.name, category: item.category, sets: item.sets, reps: item.reps, durationSec: item.durationSec, restSec: item.restSec, note: item.note, itemType: item.itemType, completed: false, })); setExercises(scheduleItems); setScheduleNote(note || ''); setHasUnsavedChanges(true); setGenVisible(false); Alert.alert('排课已生成', '已为你生成经典普拉提序列,可继续调整。'); }; // 渲染训练计划列表 const renderPlansList = () => ( 我的训练计划 点击计划卡片进入排课模式,或使用底部切换 {error && ( ⚠️ {error} )} {loading && plans.length === 0 ? ( 加载中... ) : plans.length === 0 ? ( 📋 还没有训练计划 创建你的第一个计划开始训练吧 router.push('/training-plan/create' as any)} style={styles.primaryBtn}> 创建计划 ) : ( {plans.map((p, index) => ( handlePlanSelect(p)} onDelete={() => dispatch(deletePlan(p.id))} onActivate={() => handleActivate(p.id)} onSchedule={() => handlePlanSelect(p)} /> ))} {loading && ( 处理中... )} )} ); // 渲染排课页面 const renderSchedulePage = () => { if (!selectedPlan) { return ( 📅 请先选择一个训练计划 切换到训练计划页面选择一个计划,或点击下方按钮 setActiveTab('list')} > 选择计划 ); } const goalConfig = GOAL_TEXT[selectedPlan.goal] || { title: '训练计划', color: palette.primary, description: '开始你的训练之旅' }; return ( {/* 计划信息头部 */} {selectedPlan.name || goalConfig.title} {goalConfig.description} {/* 操作按钮区域 */} 添加动作 setGenVisible(true)} > 一键排课 {/* 动作列表 */} item.key} contentContainerStyle={styles.scheduleListContent} showsVerticalScrollIndicator={false} ListEmptyComponent={ 💪 还没有添加任何动作 点击"添加动作"开始排课,或使用"一键排课"快速生成 } renderItem={({ item, index }) => { const isRest = item.itemType === 'rest'; const isNote = item.itemType === 'note'; if (isRest || isNote) { return ( {isRest ? `间隔休息 ${item.restSec ?? 30}s` : (item.note || '提示')} handleRemoveExercise(item.key)} hitSlop={{ top: 6, bottom: 6, left: 6, right: 6 }} > ); } return ( {item.name} {item.category} 组数 {item.sets} {item.reps ? ` · 每组 ${item.reps} 次` : ''} {item.durationSec ? ` · 每组 ${item.durationSec}s` : ''} handleToggleCompleted(item.key)} hitSlop={{ top: 6, bottom: 6, left: 6, right: 6 }} > handleRemoveExercise(item.key)} > 移除 ); }} /> ); }; return ( {/* 动态背景 */} router.back()} withSafeTop={false} tone='light' transparent={true} right={ activeTab === 'list' ? ( router.push('/training-plan/create' as any)} style={styles.headerRightBtn}> + 新建 ) : hasUnsavedChanges ? ( 保存 ) : undefined } /> {activeTab === 'list' ? renderPlansList() : renderSchedulePage()} {/* 底部 Tab */} {/* 一键排课配置弹窗 */} {selectedPlan && ( setGenVisible(false)}> setGenVisible(false)}> e.stopPropagation() as any}> 一键排课配置 强度水平 {(['beginner', 'intermediate', 'advanced'] as const).map((lv) => ( setGenLevel(lv)} > {lv === 'beginner' ? '入门' : lv === 'intermediate' ? '进阶' : '高级'} ))} 段间休息 插入操作提示 休息秒数 生成训练计划 )} ); } const styles = StyleSheet.create({ safeArea: { flex: 1, }, contentWrapper: { flex: 1, }, content: { paddingHorizontal: 20, paddingTop: 8, }, // 动态背景 backgroundOrb: { position: 'absolute', width: 300, height: 300, borderRadius: 150, backgroundColor: 'rgba(187,242,70,0.15)', top: -150, right: -100, }, backgroundOrb2: { position: 'absolute', width: 400, height: 400, borderRadius: 200, backgroundColor: 'rgba(164,138,237,0.12)', bottom: -200, left: -150, }, // 页面标题区域 headerSection: { marginBottom: 20, }, title: { fontSize: 28, fontWeight: '800', color: '#192126', lineHeight: 34, marginBottom: 4, }, subtitle: { fontSize: 14, color: '#5E6468', opacity: 0.8, }, // 训练计划列表 plansList: { gap: 10, }, // 训练计划卡片 planCard: { borderRadius: 28, overflow: 'hidden', shadowOffset: { width: 0, height: 10 }, shadowRadius: 20, elevation: 8, borderWidth: 1, borderColor: '#3A261B', backgroundColor: '#1F1410', shadowColor: '#000', }, cardContent: { position: 'relative', }, darkCard: { backgroundColor: '#1F1410', padding: 24, borderRadius: 28, }, cardTintGradient: { ...StyleSheet.absoluteFillObject, borderRadius: 28, }, cardGradient: { ...StyleSheet.absoluteFillObject, borderRadius: 14, }, cardGlow: { position: 'absolute', top: -2, left: -2, right: -2, bottom: -2, borderRadius: 18, backgroundColor: 'transparent', }, colorIndicator: { position: 'absolute', left: 0, top: 0, bottom: 0, width: 4, borderTopLeftRadius: 16, borderBottomLeftRadius: 16, }, cardMain: { padding: 16, paddingLeft: 20, }, cardHeader: { flexDirection: 'row', justifyContent: 'space-between', alignItems: 'flex-start', marginBottom: 12, }, titleSection: { flex: 1, }, planTitle: { fontSize: 17, fontWeight: '800', color: '#1A1E23', marginBottom: 2, }, gradientTitle: { fontSize: 34, fontWeight: '800', lineHeight: 40, color: '#FFFFFF', }, planDescription: { fontSize: 12, color: '#6A5E58', opacity: 0.9, }, darkSubtitle: { marginTop: 16, fontSize: 16, color: '#E0D2C9', lineHeight: 24, }, activeBadge: { paddingHorizontal: 8, paddingVertical: 3, borderRadius: 10, marginLeft: 8, }, activeText: { fontSize: 10, fontWeight: '800', color: palette.ink, }, cardInfo: { flexDirection: 'row', gap: 16, }, infoItem: { flex: 1, }, infoLabel: { fontSize: 10, color: '#8A7F78', marginBottom: 1, fontWeight: '600', }, infoValue: { fontSize: 13, color: '#2F2A26', fontWeight: '700', }, metricsRow: { marginTop: 28, flexDirection: 'row', alignItems: 'center', justifyContent: 'space-between', }, metricItem: { flex: 1, flexDirection: 'row', alignItems: 'center', justifyContent: 'center', paddingVertical: 8, borderRadius: 20, }, metricActive: { backgroundColor: 'rgba(255,255,255,0.06)', }, metricText: { marginLeft: 8, color: '#E6EEF2', fontSize: 16, fontWeight: '700', }, // 操作按钮区域 actionButtons: { flexDirection: 'row', marginTop: 10, gap: 6, }, actionButton: { flex: 1, paddingVertical: 6, paddingHorizontal: 8, borderRadius: 8, alignItems: 'center', justifyContent: 'center', }, scheduleButton: { backgroundColor: 'transparent', borderWidth: 1, }, activateButton: { shadowColor: '#000', shadowOffset: { width: 0, height: 2 }, shadowOpacity: 0.12, shadowRadius: 3, elevation: 3, }, activeIndicator: { borderWidth: 1.5, }, actionButtonText: { fontSize: 11, fontWeight: '700', }, activateButtonText: { fontSize: 11, fontWeight: '700', color: '#FFFFFF', }, activeIndicatorText: { fontSize: 11, fontWeight: '700', }, deleteButton: { backgroundColor: 'transparent', borderWidth: 1, borderColor: '#ED4747', }, deleteButtonText: { fontSize: 11, fontWeight: '700', color: '#ED4747', }, // 按钮样式 primaryBtn: { marginTop: 20, backgroundColor: palette.primary, paddingVertical: 14, paddingHorizontal: 28, borderRadius: 24, alignItems: 'center', shadowColor: palette.primary, shadowOffset: { width: 0, height: 4 }, shadowOpacity: 0.3, shadowRadius: 8, elevation: 6, }, primaryBtnText: { color: palette.ink, fontSize: 15, fontWeight: '800', }, createBtn: { backgroundColor: palette.primary, paddingHorizontal: 16, paddingVertical: 10, borderRadius: 22, shadowColor: palette.primary, shadowOffset: { width: 0, height: 2 }, shadowOpacity: 0.3, shadowRadius: 4, elevation: 4, minWidth: 44, minHeight: 44, alignItems: 'center', justifyContent: 'center', }, createBtnText: { color: palette.ink, fontWeight: '800', fontSize: 14, }, // 空状态 emptyWrap: { alignItems: 'center', justifyContent: 'center', paddingVertical: 60, }, emptyIcon: { width: 80, height: 80, borderRadius: 40, backgroundColor: 'rgba(187,242,70,0.1)', alignItems: 'center', justifyContent: 'center', marginBottom: 16, }, emptyIconText: { fontSize: 32, }, emptyText: { fontSize: 18, color: '#192126', fontWeight: '600', marginBottom: 4, }, emptySubtext: { fontSize: 14, color: '#5E6468', textAlign: 'center', marginBottom: 20, }, // 加载状态 loadingWrap: { alignItems: 'center', justifyContent: 'center', paddingVertical: 60, }, loadingIcon: { width: 80, height: 80, borderRadius: 40, backgroundColor: 'rgba(187,242,70,0.1)', alignItems: 'center', justifyContent: 'center', marginBottom: 16, }, loadingIconText: { fontSize: 32, }, loadingText: { fontSize: 18, color: '#192126', fontWeight: '600', marginBottom: 4, }, loadingIndicator: { alignItems: 'center', paddingVertical: 20, }, loadingIndicatorText: { fontSize: 14, color: '#5E6468', fontWeight: '600', }, // 错误状态 errorContainer: { backgroundColor: 'rgba(237,71,71,0.1)', borderRadius: 12, padding: 16, marginBottom: 16, borderWidth: 1, borderColor: 'rgba(237,71,71,0.2)', }, errorText: { fontSize: 14, color: '#ED4747', fontWeight: '600', textAlign: 'center', }, // 底部 Tab 样式(与主页一致) bottomTabContainer: { position: 'absolute', bottom: 20, // TAB_BAR_BOTTOM_OFFSET left: 0, right: 0, paddingHorizontal: 20, }, bottomTabBar: { flexDirection: 'row', height: 68, // TAB_BAR_HEIGHT borderRadius: 34, shadowColor: '#000', shadowOffset: { width: 0, height: 2 }, shadowOpacity: 0.2, shadowRadius: 10, elevation: 5, paddingHorizontal: 10, paddingTop: 0, paddingBottom: 0, marginHorizontal: 0, width: '100%', alignSelf: 'center', }, tabButton: { flex: 1, flexDirection: 'row', alignItems: 'center', justifyContent: 'center', marginHorizontal: 6, marginVertical: 10, borderRadius: 25, paddingHorizontal: 16, paddingVertical: 8, }, tabText: { fontSize: 12, fontWeight: '600', marginLeft: 6, }, // 主内容区域 mainContent: { flex: 1, paddingBottom: 100, // 为底部 tab 留出空间 }, // 排课页面样式 scheduleContent: { flex: 1, paddingHorizontal: 20, }, planHeader: { flexDirection: 'row', alignItems: 'center', padding: 16, borderRadius: 16, marginBottom: 16, }, planColorIndicator: { width: 4, height: 40, borderRadius: 2, marginRight: 12, }, planInfo: { flex: 1, }, // 排课操作按钮 actionRow: { flexDirection: 'row', gap: 12, marginBottom: 20, }, scheduleActionBtn: { flex: 1, flexDirection: 'row', alignItems: 'center', justifyContent: 'center', paddingVertical: 12, borderRadius: 12, shadowColor: '#000', shadowOffset: { width: 0, height: 2 }, shadowOpacity: 0.1, shadowRadius: 4, elevation: 4, }, scheduleActionBtnText: { color: '#FFFFFF', fontSize: 14, fontWeight: '700', }, scheduleSecondaryBtn: { flex: 1, flexDirection: 'row', alignItems: 'center', justifyContent: 'center', paddingVertical: 12, borderRadius: 12, borderWidth: 1.5, backgroundColor: '#FFFFFF', }, scheduleSecondaryBtnText: { fontSize: 14, fontWeight: '700', }, // 排课列表 scheduleListContent: { paddingBottom: 40, }, // 动作卡片 exerciseCard: { backgroundColor: '#FFFFFF', borderRadius: 16, padding: 16, marginBottom: 12, shadowColor: '#000', shadowOpacity: 0.06, shadowRadius: 12, shadowOffset: { width: 0, height: 6 }, elevation: 3, }, exerciseContent: { flexDirection: 'row', alignItems: 'center', }, exerciseInfo: { flex: 1, }, exerciseName: { fontSize: 16, fontWeight: '800', color: '#192126', marginBottom: 4, }, exerciseCategory: { fontSize: 12, color: '#888F92', marginBottom: 4, }, exerciseMeta: { fontSize: 12, color: '#5E6468', }, exerciseActions: { flexDirection: 'row', alignItems: 'center', gap: 12, }, completeBtn: { padding: 4, }, removeBtn: { backgroundColor: '#F3F4F6', paddingHorizontal: 10, paddingVertical: 6, borderRadius: 8, }, removeBtnText: { color: '#384046', fontWeight: '700', fontSize: 12, }, // 内联项目(休息、提示) inlineRow: { flexDirection: 'row', alignItems: 'center', marginBottom: 10, }, inlineBadge: { marginLeft: 6, borderWidth: 1, borderColor: '#E5E7EB', borderRadius: 999, paddingVertical: 6, paddingHorizontal: 10, flex: 1, }, inlineBadgeRest: { backgroundColor: '#F8FAFC', }, inlineBadgeNote: { backgroundColor: '#F9FAFB', }, inlineText: { fontSize: 12, fontWeight: '700', }, inlineTextItalic: { fontSize: 12, fontStyle: 'italic', }, inlineRemoveBtn: { marginLeft: 6, padding: 4, borderRadius: 999, }, // 空状态(排课页面) emptyContainer: { alignItems: 'center', justifyContent: 'center', paddingVertical: 60, }, // 未选择计划状态 noSelectionContainer: { flex: 1, alignItems: 'center', justifyContent: 'center', paddingVertical: 60, paddingHorizontal: 20, }, noSelectionIcon: { width: 80, height: 80, borderRadius: 40, backgroundColor: 'rgba(187,242,70,0.1)', alignItems: 'center', justifyContent: 'center', marginBottom: 16, }, noSelectionIconText: { fontSize: 32, }, noSelectionText: { fontSize: 18, color: '#192126', fontWeight: '600', marginBottom: 4, textAlign: 'center', }, noSelectionSubtext: { fontSize: 14, color: '#5E6468', textAlign: 'center', marginBottom: 20, }, // 弹窗样式 modalOverlay: { flex: 1, backgroundColor: 'rgba(0,0,0,0.35)', alignItems: 'center', justifyContent: 'flex-end', }, modalSheet: { width: '100%', backgroundColor: '#FFFFFF', borderTopLeftRadius: 16, borderTopRightRadius: 16, paddingHorizontal: 16, paddingTop: 14, paddingBottom: 24, }, modalTitle: { fontSize: 16, fontWeight: '800', marginBottom: 16, color: '#192126', }, modalLabel: { fontSize: 12, color: '#888F92', marginBottom: 8, fontWeight: '600', }, segmentedRow: { flexDirection: 'row', gap: 8, marginBottom: 16, }, segment: { flex: 1, borderRadius: 999, borderWidth: 1, borderColor: '#E5E7EB', paddingVertical: 8, alignItems: 'center', }, segmentText: { fontWeight: '700', color: '#384046', }, switchRow: { flexDirection: 'row', alignItems: 'center', justifyContent: 'space-between', marginBottom: 12, }, switchLabel: { fontWeight: '700', color: '#384046', }, inputRow: { marginBottom: 20, }, inputLabel: { fontSize: 12, color: '#888F92', marginBottom: 8, fontWeight: '600', }, input: { height: 40, borderWidth: 1, borderColor: '#E5E7EB', borderRadius: 10, paddingHorizontal: 12, color: '#384046', }, generateBtn: { paddingVertical: 12, borderRadius: 12, alignItems: 'center', }, generateBtnText: { color: '#FFFFFF', fontWeight: '800', fontSize: 14, }, // 顶部导航右侧按钮(与 HeaderBar 标准尺寸一致,使用 tab 配色) headerRightBtn: { width: 52, height: 32, backgroundColor: palette.primary, // 使用 tab 的主色 borderRadius: 16, alignItems: 'center', justifyContent: 'center', }, headerRightBtnText: { color: palette.ink, fontWeight: '800', fontSize: 10, }, });