feat: 更新应用配置和引入新依赖

- 修改 app.json,禁用平板支持以优化用户体验
- 在 package.json 和 package-lock.json 中新增 react-native-toast-message 依赖,支持消息提示功能
- 在多个组件中集成 Toast 组件,提升用户交互反馈
- 更新训练计划相关逻辑,优化状态管理和数据处理
- 调整样式以适应新功能的展示和交互
This commit is contained in:
2025-08-16 09:42:33 +08:00
parent 3312250f2d
commit 5a4d86ff7d
16 changed files with 192 additions and 255 deletions

View File

@@ -1,8 +1,8 @@
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 { useFocusEffect, useLocalSearchParams, useRouter } from 'expo-router';
import React, { useCallback, useEffect, useMemo, useState } from 'react';
import { Alert, FlatList, Modal, Pressable, SafeAreaView, ScrollView, StyleSheet, Switch, Text, TextInput, TouchableOpacity, View } from 'react-native';
import Animated, {
FadeInUp,
@@ -21,6 +21,7 @@ import { HeaderBar } from '@/components/ui/HeaderBar';
import { Colors, palette } from '@/constants/Colors';
import { useAppDispatch, useAppSelector } from '@/hooks/redux';
import { useColorScheme } from '@/hooks/useColorScheme';
import { TrainingPlan } from '@/services/trainingPlanApi';
import {
addExercise,
clearExercises,
@@ -29,7 +30,7 @@ import {
loadExercises,
toggleCompletion
} from '@/store/scheduleExerciseSlice';
import { activatePlan, clearError, deletePlan, loadPlans, type TrainingPlan } from '@/store/trainingPlanSlice';
import { activatePlan, clearError, deletePlan, loadPlans } from '@/store/trainingPlanSlice';
import { buildClassicalSession } from '@/utils/classicalSession';
// Tab 类型定义
@@ -248,13 +249,14 @@ export default function TrainingPlanScreen() {
const router = useRouter();
const dispatch = useAppDispatch();
const params = useLocalSearchParams<{ planId?: string; tab?: string }>();
const { plans, currentId, loading, error } = useAppSelector((s) => s.trainingPlan);
const { plans, loading, error } = useAppSelector((s) => s.trainingPlan);
const { exercises, error: scheduleError } = useAppSelector((s) => s.scheduleExercise);
console.log('plans', plans);
// Tab 状态管理 - 支持从URL参数设置初始tab
const initialTab: TabType = params.tab === 'schedule' ? 'schedule' : 'list';
const [activeTab, setActiveTab] = useState<TabType>(initialTab);
const [selectedPlanId, setSelectedPlanId] = useState<string | null>(params.planId || currentId || null);
const [selectedPlanId, setSelectedPlanId] = useState<string | null>(params.planId || null);
// 一键排课配置
const [genVisible, setGenVisible] = useState(false);
@@ -274,9 +276,21 @@ export default function TrainingPlanScreen() {
}
}, [selectedPlanId, dispatch]);
useEffect(() => {
dispatch(loadPlans());
}, [dispatch]);
// 每次页面获得焦点时,如果当前有选中的计划,重新加载其排课数据
useFocusEffect(
useCallback(() => {
if (selectedPlanId) {
dispatch(loadExercises(selectedPlanId));
}
}, [selectedPlanId, dispatch])
);
// 每次页面获得焦点时重新加载训练计划数据
useFocusEffect(
useCallback(() => {
dispatch(loadPlans());
}, [dispatch])
);
useEffect(() => {
if (error) {
@@ -314,7 +328,7 @@ export default function TrainingPlanScreen() {
const handleTabChange = (tab: TabType) => {
if (tab === 'schedule' && !selectedPlanId && plans.length > 0) {
// 如果没有选中计划但要切换到排课页面,自动选择当前激活的计划或第一个计划
const targetPlan = plans.find(p => p.id === currentId) || plans[0];
const targetPlan = plans.find(p => p.isActive) || plans[0];
setSelectedPlanId(targetPlan.id);
}
setActiveTab(tab);
@@ -426,7 +440,7 @@ export default function TrainingPlanScreen() {
key={p.id}
plan={p}
index={index}
isActive={p.id === currentId}
isActive={p.isActive}
onPress={() => handlePlanSelect(p)}
onDelete={() => dispatch(deletePlan(p.id))}
onActivate={() => handleActivate(p.id)}
@@ -1098,7 +1112,7 @@ const styles = StyleSheet.create({
// 主内容区域
mainContent: {
flex: 1,
paddingBottom: 100, // 为底部 tab 留出空间
paddingBottom: 60, // 为底部 tab 留出空间
},
// 排课页面样式