Enhance App structure by integrating TasksProvider; update BottomActionBar and TaskCard components to use React Native Paper; implement dropdowns in TaskForm; refactor TaskEditScreen and TaskListScreen to utilize context for task management.
This commit is contained in:
parent
ea68167afb
commit
5ecb12a679
9
App.tsx
9
App.tsx
@ -2,14 +2,17 @@ import React from 'react';
|
|||||||
import { NavigationContainer } from '@react-navigation/native';
|
import { NavigationContainer } from '@react-navigation/native';
|
||||||
import AppNavigator from './src/navigation/AppNavigator';
|
import AppNavigator from './src/navigation/AppNavigator';
|
||||||
|
|
||||||
|
import { TasksProvider } from './src/context/TasksContext';
|
||||||
import { PaperProvider } from 'react-native-paper';
|
import { PaperProvider } from 'react-native-paper';
|
||||||
|
|
||||||
export default function App() {
|
export default function App() {
|
||||||
return (
|
return (
|
||||||
<PaperProvider>
|
<PaperProvider>
|
||||||
<NavigationContainer>
|
<TasksProvider>
|
||||||
<AppNavigator />
|
<NavigationContainer>
|
||||||
</NavigationContainer>
|
<AppNavigator />
|
||||||
|
</NavigationContainer>
|
||||||
|
</TasksProvider>
|
||||||
</PaperProvider>
|
</PaperProvider>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
18
package-lock.json
generated
18
package-lock.json
generated
@ -17,6 +17,7 @@
|
|||||||
"react-native-gesture-handler": "^2.27.1",
|
"react-native-gesture-handler": "^2.27.1",
|
||||||
"react-native-get-random-values": "^1.11.0",
|
"react-native-get-random-values": "^1.11.0",
|
||||||
"react-native-paper": "^5.14.5",
|
"react-native-paper": "^5.14.5",
|
||||||
|
"react-native-paper-dropdown": "^2.3.1",
|
||||||
"react-native-safe-area-context": "^5.5.2",
|
"react-native-safe-area-context": "^5.5.2",
|
||||||
"react-native-screens": "^4.13.1",
|
"react-native-screens": "^4.13.1",
|
||||||
"react-native-vector-icons": "^10.2.0",
|
"react-native-vector-icons": "^10.2.0",
|
||||||
@ -10826,6 +10827,23 @@
|
|||||||
"react-native-safe-area-context": "*"
|
"react-native-safe-area-context": "*"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/react-native-paper-dropdown": {
|
||||||
|
"version": "2.3.1",
|
||||||
|
"resolved": "https://registry.npmmirror.com/react-native-paper-dropdown/-/react-native-paper-dropdown-2.3.1.tgz",
|
||||||
|
"integrity": "sha512-IvcHTucAV5+fiX2IVMiVdBDKT6KHxycW0o9QzZe7bpmeZWmuCajHDnwG3OSBGlXhUxrrM3TC0/HJZHwORWGgQg==",
|
||||||
|
"license": "MIT",
|
||||||
|
"workspaces": [
|
||||||
|
"example"
|
||||||
|
],
|
||||||
|
"dependencies": {
|
||||||
|
"react-native-paper": "^5.12.3"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"react": "*",
|
||||||
|
"react-native": "*",
|
||||||
|
"react-native-paper": "*"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/react-native-paper/node_modules/color": {
|
"node_modules/react-native-paper/node_modules/color": {
|
||||||
"version": "3.2.1",
|
"version": "3.2.1",
|
||||||
"resolved": "https://registry.npmmirror.com/color/-/color-3.2.1.tgz",
|
"resolved": "https://registry.npmmirror.com/color/-/color-3.2.1.tgz",
|
||||||
|
@ -19,6 +19,7 @@
|
|||||||
"react-native-gesture-handler": "^2.27.1",
|
"react-native-gesture-handler": "^2.27.1",
|
||||||
"react-native-get-random-values": "^1.11.0",
|
"react-native-get-random-values": "^1.11.0",
|
||||||
"react-native-paper": "^5.14.5",
|
"react-native-paper": "^5.14.5",
|
||||||
|
"react-native-paper-dropdown": "^2.3.1",
|
||||||
"react-native-safe-area-context": "^5.5.2",
|
"react-native-safe-area-context": "^5.5.2",
|
||||||
"react-native-screens": "^4.13.1",
|
"react-native-screens": "^4.13.1",
|
||||||
"react-native-vector-icons": "^10.2.0",
|
"react-native-vector-icons": "^10.2.0",
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { View, Button, StyleSheet } from 'react-native';
|
import { Appbar, useTheme } from 'react-native-paper';
|
||||||
|
import { StyleSheet } from 'react-native';
|
||||||
|
|
||||||
interface BottomActionBarProps {
|
interface BottomActionBarProps {
|
||||||
onRun: () => void;
|
onRun: () => void;
|
||||||
@ -18,25 +19,26 @@ const BottomActionBar: React.FC<BottomActionBarProps> = ({
|
|||||||
onBack,
|
onBack,
|
||||||
isSaveDisabled = true,
|
isSaveDisabled = true,
|
||||||
}) => {
|
}) => {
|
||||||
|
const theme = useTheme();
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<View style={styles.container}>
|
<Appbar style={[styles.bottom, { backgroundColor: theme.colors.elevation.level2 }]}>
|
||||||
<Button title="运行" onPress={onRun} />
|
<Appbar.Action icon="arrow-left" onPress={onBack} />
|
||||||
<Button title="保存" onPress={onSave} disabled={isSaveDisabled} />
|
<Appbar.Action icon="play" onPress={onRun} />
|
||||||
<Button title="撤销" onPress={onUndo} />
|
<Appbar.Action icon="content-save" onPress={onSave} disabled={isSaveDisabled} />
|
||||||
<Button title="恢复" onPress={onRestore} />
|
<Appbar.Action icon="undo" onPress={onUndo} />
|
||||||
<Button title="返回" onPress={onBack} />
|
<Appbar.Action icon="restore" onPress={onRestore} />
|
||||||
</View>
|
</Appbar>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
const styles = StyleSheet.create({
|
const styles = StyleSheet.create({
|
||||||
container: {
|
bottom: {
|
||||||
flexDirection: 'row',
|
position: 'absolute',
|
||||||
|
left: 0,
|
||||||
|
right: 0,
|
||||||
|
bottom: 0,
|
||||||
justifyContent: 'space-around',
|
justifyContent: 'space-around',
|
||||||
padding: 16,
|
|
||||||
borderTopWidth: 1,
|
|
||||||
borderColor: '#ccc',
|
|
||||||
backgroundColor: '#f5f5f5',
|
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -1,43 +1,52 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { View, Text, StyleSheet, TouchableOpacity } from 'react-native';
|
import { StyleSheet } from 'react-native';
|
||||||
import { Task } from '../types/task';
|
import { Card, Text, Chip, useTheme } from 'react-native-paper';
|
||||||
|
import { Task, TaskStatus } from '../types/task';
|
||||||
|
|
||||||
interface TaskCardProps {
|
interface TaskCardProps {
|
||||||
task: Task;
|
task: Task;
|
||||||
onPress: (id: string) => void;
|
onPress: (id: string) => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const statusColors: Record<TaskStatus, string> = {
|
||||||
|
IDLE: 'grey',
|
||||||
|
RUNNING: 'blue',
|
||||||
|
COMPLETED: 'green',
|
||||||
|
ERROR: 'red',
|
||||||
|
};
|
||||||
|
|
||||||
const TaskCard: React.FC<TaskCardProps> = ({ task, onPress }) => {
|
const TaskCard: React.FC<TaskCardProps> = ({ task, onPress }) => {
|
||||||
|
const theme = useTheme();
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<TouchableOpacity style={styles.card} onPress={() => onPress(task.id)}>
|
<Card style={styles.card} onPress={() => onPress(task.id)}>
|
||||||
<Text style={styles.title}>{task.name}</Text>
|
<Card.Content>
|
||||||
<Text style={styles.status}>状态: {task.status}</Text>
|
<Text variant="titleMedium" style={styles.title}>{task.name}</Text>
|
||||||
</TouchableOpacity>
|
<Chip
|
||||||
|
icon="information"
|
||||||
|
mode="outlined"
|
||||||
|
selectedColor={statusColors[task.status]}
|
||||||
|
style={[styles.chip, {backgroundColor: theme.colors.surface}]}
|
||||||
|
>
|
||||||
|
{task.status}
|
||||||
|
</Chip>
|
||||||
|
</Card.Content>
|
||||||
|
</Card>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
const styles = StyleSheet.create({
|
const styles = StyleSheet.create({
|
||||||
card: {
|
card: {
|
||||||
backgroundColor: '#fff',
|
|
||||||
borderRadius: 8,
|
|
||||||
padding: 16,
|
|
||||||
margin: 8,
|
margin: 8,
|
||||||
width: '45%',
|
width: '45%',
|
||||||
elevation: 3,
|
|
||||||
shadowColor: '#000',
|
|
||||||
shadowOffset: { width: 0, height: 2 },
|
|
||||||
shadowOpacity: 0.1,
|
|
||||||
shadowRadius: 2,
|
|
||||||
},
|
},
|
||||||
title: {
|
title: {
|
||||||
fontSize: 16,
|
marginBottom: 12,
|
||||||
fontWeight: 'bold',
|
minHeight: 50, // Ensure cards have similar height
|
||||||
marginBottom: 8,
|
|
||||||
},
|
|
||||||
status: {
|
|
||||||
fontSize: 14,
|
|
||||||
color: '#666',
|
|
||||||
},
|
},
|
||||||
|
chip: {
|
||||||
|
alignSelf: 'flex-start',
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
export default TaskCard;
|
export default TaskCard;
|
||||||
|
@ -1,6 +1,9 @@
|
|||||||
import React from 'react';
|
import React, { useState } from 'react';
|
||||||
import { View, Text, TextInput, StyleSheet, ScrollView } from 'react-native';
|
import { View, StyleSheet, ScrollView } from 'react-native';
|
||||||
|
import { TextInput } from 'react-native-paper';
|
||||||
|
import DropDown from "react-native-paper-dropdown";
|
||||||
import { Task, RobotAction } from '../types/task';
|
import { Task, RobotAction } from '../types/task';
|
||||||
|
import { LOCATIONS, ROBOT_ACTIONS, PAYLOADS } from '../data/mockData';
|
||||||
|
|
||||||
interface TaskFormProps {
|
interface TaskFormProps {
|
||||||
task: Task;
|
task: Task;
|
||||||
@ -8,7 +11,12 @@ interface TaskFormProps {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const TaskForm: React.FC<TaskFormProps> = ({ task, onTaskChange }) => {
|
const TaskForm: React.FC<TaskFormProps> = ({ task, onTaskChange }) => {
|
||||||
const handleParamChange = (field: string, value: string) => {
|
const [showStartLocation, setShowStartLocation] = useState(false);
|
||||||
|
const [showEndLocation, setShowEndLocation] = useState(false);
|
||||||
|
const [showRobotAction, setShowRobotAction] = useState(false);
|
||||||
|
const [showPayload, setShowPayload] = useState(false);
|
||||||
|
|
||||||
|
const handleParamChange = (field: string, value: string | RobotAction) => {
|
||||||
const updatedTask = {
|
const updatedTask = {
|
||||||
...task,
|
...task,
|
||||||
parameters: {
|
parameters: {
|
||||||
@ -20,85 +28,120 @@ const TaskForm: React.FC<TaskFormProps> = ({ task, onTaskChange }) => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<ScrollView style={styles.container}>
|
<ScrollView contentContainerStyle={styles.container}>
|
||||||
<View style={styles.fieldContainer}>
|
|
||||||
<Text style={styles.label}>任务名称</Text>
|
|
||||||
<TextInput
|
<TextInput
|
||||||
style={styles.input}
|
label="任务名称"
|
||||||
value={task.name}
|
value={task.name}
|
||||||
onChangeText={text => onTaskChange({ ...task, name: text })}
|
onChangeText={text => onTaskChange({ ...task, name: text })}
|
||||||
|
style={styles.input}
|
||||||
|
mode="outlined"
|
||||||
/>
|
/>
|
||||||
</View>
|
|
||||||
|
|
||||||
<View style={styles.fieldContainer}>
|
{/* <DropDown
|
||||||
<Text style={styles.label}>起点</Text>
|
label={"起点"}
|
||||||
|
mode={"outlined"}
|
||||||
|
visible={showStartLocation}
|
||||||
|
showDropDown={() => setShowStartLocation(true)}
|
||||||
|
onDismiss={() => setShowStartLocation(false)}
|
||||||
|
value={task.parameters.startLocation}
|
||||||
|
setValue={(value) => handleParamChange('startLocation', value)}
|
||||||
|
list={LOCATIONS.map((location) => ({
|
||||||
|
label: location.label,
|
||||||
|
value: location.value,
|
||||||
|
}))}
|
||||||
|
dropDownStyle={styles.input}
|
||||||
|
/> */}
|
||||||
<TextInput
|
<TextInput
|
||||||
style={styles.input}
|
label="起点"
|
||||||
value={task.parameters.startLocation}
|
value={task.parameters.startLocation}
|
||||||
onChangeText={text => handleParamChange('startLocation', text)}
|
onChangeText={text => handleParamChange('startLocation', text)}
|
||||||
|
style={styles.input}
|
||||||
|
mode="outlined"
|
||||||
/>
|
/>
|
||||||
</View>
|
|
||||||
|
|
||||||
<View style={styles.fieldContainer}>
|
{/* <DropDown
|
||||||
<Text style={styles.label}>终点</Text>
|
label={"终点"}
|
||||||
|
mode={"outlined"}
|
||||||
|
visible={showEndLocation}
|
||||||
|
showDropDown={() => setShowEndLocation(true)}
|
||||||
|
onDismiss={() => setShowEndLocation(false)}
|
||||||
|
value={task.parameters.endLocation}
|
||||||
|
setValue={(value) => handleParamChange('endLocation', value)}
|
||||||
|
list={LOCATIONS.map((location) => ({
|
||||||
|
label: location.label,
|
||||||
|
value: location.value,
|
||||||
|
}))}
|
||||||
|
dropDownStyle={styles.input}
|
||||||
|
/> */}
|
||||||
<TextInput
|
<TextInput
|
||||||
style={styles.input}
|
label="终点"
|
||||||
value={task.parameters.endLocation}
|
value={task.parameters.endLocation}
|
||||||
onChangeText={text => handleParamChange('endLocation', text)}
|
onChangeText={text => handleParamChange('endLocation', text)}
|
||||||
|
style={styles.input}
|
||||||
|
mode="outlined"
|
||||||
/>
|
/>
|
||||||
</View>
|
|
||||||
|
|
||||||
<View style={styles.fieldContainer}>
|
|
||||||
<Text style={styles.label}>途经点</Text>
|
|
||||||
<TextInput
|
<TextInput
|
||||||
style={styles.input}
|
label="途经点 (可选)"
|
||||||
value={task.parameters.waypoint || ''}
|
value={task.parameters.waypoint || ''}
|
||||||
onChangeText={text => handleParamChange('waypoint', text)}
|
onChangeText={text => handleParamChange('waypoint', text)}
|
||||||
placeholder="可选"
|
style={styles.input}
|
||||||
|
mode="outlined"
|
||||||
|
/>
|
||||||
|
|
||||||
|
{/* <DropDown
|
||||||
|
label={"机器人动作"}
|
||||||
|
mode={"outlined"}
|
||||||
|
visible={showRobotAction}
|
||||||
|
showDropDown={() => setShowRobotAction(true)}
|
||||||
|
onDismiss={() => setShowRobotAction(false)}
|
||||||
|
value={task.parameters.robotAction}
|
||||||
|
setValue={(value) => handleParamChange('robotAction', value)}
|
||||||
|
list={ROBOT_ACTIONS.map((action) => ({
|
||||||
|
label: action.label,
|
||||||
|
value: action.value,
|
||||||
|
}))}
|
||||||
|
dropDownStyle={styles.input}
|
||||||
|
/> */}
|
||||||
|
<TextInput
|
||||||
|
label="机器人动作"
|
||||||
|
value={task.parameters.robotAction}
|
||||||
|
onChangeText={text => handleParamChange('robotAction', text)}
|
||||||
|
style={styles.input}
|
||||||
|
mode="outlined"
|
||||||
/>
|
/>
|
||||||
</View>
|
|
||||||
|
|
||||||
<View style={styles.fieldContainer}>
|
{/* <DropDown
|
||||||
<Text style={styles.label}>机器人动作</Text>
|
label={"载荷"}
|
||||||
{/* 在实际应用中,这里最好是一个下拉选择器 */}
|
mode={"outlined"}
|
||||||
|
visible={showPayload}
|
||||||
|
showDropDown={() => setShowPayload(true)}
|
||||||
|
onDismiss={() => setShowPayload(false)}
|
||||||
|
value={task.parameters.payload}
|
||||||
|
setValue={(value) => handleParamChange('payload', value)}
|
||||||
|
list={PAYLOADS.map((payload) => ({
|
||||||
|
label: payload.label,
|
||||||
|
value: payload.value,
|
||||||
|
}))}
|
||||||
|
dropDownStyle={styles.input}
|
||||||
|
/> */}
|
||||||
<TextInput
|
<TextInput
|
||||||
style={styles.input}
|
label="载荷"
|
||||||
value={task.parameters.robotAction}
|
value={task.parameters.payload}
|
||||||
onChangeText={text => handleParamChange('robotAction', text as RobotAction)}
|
onChangeText={text => handleParamChange('payload', text)}
|
||||||
|
style={styles.input}
|
||||||
|
mode="outlined"
|
||||||
/>
|
/>
|
||||||
</View>
|
|
||||||
|
|
||||||
<View style={styles.fieldContainer}>
|
|
||||||
<Text style={styles.label}>载荷</Text>
|
|
||||||
<TextInput
|
|
||||||
style={styles.input}
|
|
||||||
value={task.parameters.payload}
|
|
||||||
onChangeText={text => handleParamChange('payload', text)}
|
|
||||||
/>
|
|
||||||
</View>
|
|
||||||
</ScrollView>
|
</ScrollView>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
const styles = StyleSheet.create({
|
const styles = StyleSheet.create({
|
||||||
container: {
|
container: {
|
||||||
flex: 1,
|
|
||||||
padding: 16,
|
padding: 16,
|
||||||
},
|
},
|
||||||
fieldContainer: {
|
|
||||||
marginBottom: 16,
|
|
||||||
},
|
|
||||||
label: {
|
|
||||||
fontSize: 16,
|
|
||||||
marginBottom: 8,
|
|
||||||
fontWeight: 'bold',
|
|
||||||
},
|
|
||||||
input: {
|
input: {
|
||||||
borderWidth: 1,
|
marginBottom: 16,
|
||||||
borderColor: '#ccc',
|
|
||||||
borderRadius: 4,
|
|
||||||
padding: 12,
|
|
||||||
fontSize: 16,
|
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
52
src/context/TasksContext.tsx
Normal file
52
src/context/TasksContext.tsx
Normal file
@ -0,0 +1,52 @@
|
|||||||
|
import React, { createContext, useState, useContext, ReactNode } from 'react';
|
||||||
|
import { Task } from '../types/task';
|
||||||
|
import { MOCK_TASKS } from '../data/mockData';
|
||||||
|
|
||||||
|
interface TasksContextData {
|
||||||
|
tasks: Task[];
|
||||||
|
getTaskById: (id: string) => Task | undefined;
|
||||||
|
updateTask: (updatedTask: Task) => void;
|
||||||
|
runTask: (id: string) => void;
|
||||||
|
}
|
||||||
|
|
||||||
|
const TasksContext = createContext<TasksContextData>({} as TasksContextData);
|
||||||
|
|
||||||
|
export const TasksProvider: React.FC<{children: ReactNode}> = ({ children }) => {
|
||||||
|
const [tasks, setTasks] = useState<Task[]>(MOCK_TASKS);
|
||||||
|
|
||||||
|
const getTaskById = (id: string) => {
|
||||||
|
return tasks.find(task => task.id === id);
|
||||||
|
};
|
||||||
|
|
||||||
|
const updateTask = (updatedTask: Task) => {
|
||||||
|
setTasks(prevTasks =>
|
||||||
|
prevTasks.map(task => (task.id === updatedTask.id ? updatedTask : task))
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
const runTask = (id: string) => {
|
||||||
|
setTasks(prevTasks =>
|
||||||
|
prevTasks.map(task =>
|
||||||
|
task.id === id ? { ...task, status: 'RUNNING' } : task
|
||||||
|
)
|
||||||
|
);
|
||||||
|
// 模拟任务完成
|
||||||
|
setTimeout(() => {
|
||||||
|
setTasks(prevTasks =>
|
||||||
|
prevTasks.map(task =>
|
||||||
|
task.id === id ? { ...task, status: 'COMPLETED' } : task
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}, 5000);
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<TasksContext.Provider value={{ tasks, getTaskById, updateTask, runTask }}>
|
||||||
|
{children}
|
||||||
|
</TasksContext.Provider>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export function useTasks() {
|
||||||
|
return useContext(TasksContext);
|
||||||
|
}
|
@ -1,6 +1,30 @@
|
|||||||
import { Task } from '../types/task';
|
import { Task, RobotAction } from '../types/task';
|
||||||
import { v4 as uuidv4 } from 'uuid';
|
import { v4 as uuidv4 } from 'uuid';
|
||||||
|
|
||||||
|
export const LOCATIONS = [
|
||||||
|
{ label: '炉前缓存区', value: '炉前缓存区' },
|
||||||
|
{ label: '热处理上料交接区', value: '热处理上料交接区' },
|
||||||
|
{ label: '空料架缓存区', value: '空料架缓存区' },
|
||||||
|
{ label: '焊接空料架交接区', value: '焊接空料架交接区' },
|
||||||
|
{ label: '热后区', value: '热后区' },
|
||||||
|
{ label: 'ALD上料区', value: 'ALD上料区' },
|
||||||
|
{ label: '空车区', value: '空车区' },
|
||||||
|
];
|
||||||
|
|
||||||
|
export const ROBOT_ACTIONS: { label: string; value: RobotAction }[] = [
|
||||||
|
{ label: '运输', value: 'TRANSPORT' },
|
||||||
|
{ label: '取货', value: 'PICKUP' },
|
||||||
|
{ label: '卸货', value: 'DROPOFF' },
|
||||||
|
{ label: '等待', value: 'WAIT' },
|
||||||
|
];
|
||||||
|
|
||||||
|
export const PAYLOADS = [
|
||||||
|
{ label: '满料架-A1', value: '满料架-A1' },
|
||||||
|
{ label: '空料架-B2', value: '空料架-B2' },
|
||||||
|
{ label: '空料架-C3', value: '空料架-C3' },
|
||||||
|
{ label: '空车', value: '空车' },
|
||||||
|
];
|
||||||
|
|
||||||
export const MOCK_TASKS: Task[] = [
|
export const MOCK_TASKS: Task[] = [
|
||||||
{
|
{
|
||||||
id: uuidv4(),
|
id: uuidv4(),
|
||||||
|
@ -2,11 +2,11 @@ import React, { useState, useEffect } from 'react';
|
|||||||
import { View, StyleSheet, Alert } from 'react-native';
|
import { View, StyleSheet, Alert } from 'react-native';
|
||||||
import { useRoute, useNavigation } from '@react-navigation/native';
|
import { useRoute, useNavigation } from '@react-navigation/native';
|
||||||
import { RouteProp } from '@react-navigation/native';
|
import { RouteProp } from '@react-navigation/native';
|
||||||
|
import { useTasks } from '../context/TasksContext';
|
||||||
import TaskForm from '../components/TaskForm';
|
import TaskForm from '../components/TaskForm';
|
||||||
import BottomActionBar from '../components/BottomActionBar';
|
import BottomActionBar from '../components/BottomActionBar';
|
||||||
import { Task } from '../types/task';
|
import { Task } from '../types/task';
|
||||||
|
import { ActivityIndicator } from 'react-native-paper';
|
||||||
import { MOCK_TASKS } from '../data/mockData';
|
|
||||||
|
|
||||||
type RootStackParamList = {
|
type RootStackParamList = {
|
||||||
TaskEdit: { taskId: string };
|
TaskEdit: { taskId: string };
|
||||||
@ -19,16 +19,19 @@ export default function TaskEditScreen() {
|
|||||||
const navigation = useNavigation();
|
const navigation = useNavigation();
|
||||||
const { taskId } = route.params;
|
const { taskId } = route.params;
|
||||||
|
|
||||||
|
const { getTaskById, updateTask, runTask } = useTasks();
|
||||||
|
|
||||||
const [task, setTask] = useState<Task | null>(null);
|
const [task, setTask] = useState<Task | null>(null);
|
||||||
|
const [originalTask, setOriginalTask] = useState<Task | null>(null);
|
||||||
const [isModified, setIsModified] = useState(false);
|
const [isModified, setIsModified] = useState(false);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
// 根据taskId从模拟数据中查找任务
|
const foundTask = getTaskById(taskId);
|
||||||
const foundTask = MOCK_TASKS.find(t => t.id === taskId);
|
|
||||||
if (foundTask) {
|
if (foundTask) {
|
||||||
setTask(foundTask);
|
setTask(foundTask);
|
||||||
|
setOriginalTask(foundTask);
|
||||||
}
|
}
|
||||||
}, [taskId]);
|
}, [taskId, getTaskById]);
|
||||||
|
|
||||||
const handleTaskChange = (updatedTask: Task) => {
|
const handleTaskChange = (updatedTask: Task) => {
|
||||||
setTask(updatedTask);
|
setTask(updatedTask);
|
||||||
@ -38,23 +41,43 @@ export default function TaskEditScreen() {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const handleSave = () => {
|
const handleSave = () => {
|
||||||
// 在这里处理保存逻辑,比如调用API
|
if (task) {
|
||||||
Alert.alert('已保存', `任务 "${task?.name}" 已被保存。`);
|
updateTask(task);
|
||||||
setIsModified(false);
|
setOriginalTask(task);
|
||||||
|
setIsModified(false);
|
||||||
|
Alert.alert('已保存', `任务 "${task.name}" 已被保存。`);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const handleRun = () => {
|
||||||
|
if(task) {
|
||||||
|
runTask(task.id);
|
||||||
|
navigation.goBack();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const handleUndo = () => {
|
||||||
|
setTask(originalTask);
|
||||||
|
setIsModified(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
const handleRestore = () => {
|
||||||
|
setTask(originalTask);
|
||||||
|
setIsModified(false);
|
||||||
|
}
|
||||||
|
|
||||||
if (!task) {
|
if (!task) {
|
||||||
return null; // 或者显示一个加载指示器
|
return <ActivityIndicator animating={true} size="large" style={styles.loader}/>;
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<View style={styles.container}>
|
<View style={styles.container}>
|
||||||
<TaskForm task={task} onTaskChange={handleTaskChange} />
|
<TaskForm task={task} onTaskChange={handleTaskChange} />
|
||||||
<BottomActionBar
|
<BottomActionBar
|
||||||
onRun={() => Alert.alert('运行', '开始运行任务...')}
|
onRun={handleRun}
|
||||||
onSave={handleSave}
|
onSave={handleSave}
|
||||||
onUndo={() => Alert.alert('撤销', '撤销更改...')}
|
onUndo={handleUndo}
|
||||||
onRestore={() => Alert.alert('恢复', '恢复到初始状态...')}
|
onRestore={handleRestore}
|
||||||
onBack={() => navigation.goBack()}
|
onBack={() => navigation.goBack()}
|
||||||
isSaveDisabled={!isModified}
|
isSaveDisabled={!isModified}
|
||||||
/>
|
/>
|
||||||
@ -67,4 +90,9 @@ const styles = StyleSheet.create({
|
|||||||
flex: 1,
|
flex: 1,
|
||||||
backgroundColor: '#fff',
|
backgroundColor: '#fff',
|
||||||
},
|
},
|
||||||
|
loader: {
|
||||||
|
flex: 1,
|
||||||
|
justifyContent: 'center',
|
||||||
|
alignItems: 'center'
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
@ -1,10 +1,9 @@
|
|||||||
import React, { useState } from 'react';
|
import React from 'react';
|
||||||
import { View, FlatList, StyleSheet } from 'react-native';
|
import { View, FlatList, StyleSheet } from 'react-native';
|
||||||
import { useNavigation } from '@react-navigation/native';
|
import { useNavigation } from '@react-navigation/native';
|
||||||
import { StackNavigationProp } from '@react-navigation/stack';
|
import { StackNavigationProp } from '@react-navigation/stack';
|
||||||
|
import { useTasks } from '../context/TasksContext';
|
||||||
import TaskCard from '../components/TaskCard';
|
import TaskCard from '../components/TaskCard';
|
||||||
import { Task } from '../types/task';
|
|
||||||
import { MOCK_TASKS } from '../data/mockData';
|
|
||||||
|
|
||||||
type RootStackParamList = {
|
type RootStackParamList = {
|
||||||
TaskList: undefined;
|
TaskList: undefined;
|
||||||
@ -14,7 +13,7 @@ type RootStackParamList = {
|
|||||||
type TaskListNavigationProp = StackNavigationProp<RootStackParamList, 'TaskList'>;
|
type TaskListNavigationProp = StackNavigationProp<RootStackParamList, 'TaskList'>;
|
||||||
|
|
||||||
export default function TaskListScreen() {
|
export default function TaskListScreen() {
|
||||||
const [tasks] = useState<Task[]>(MOCK_TASKS);
|
const { tasks } = useTasks();
|
||||||
const navigation = useNavigation<TaskListNavigationProp>();
|
const navigation = useNavigation<TaskListNavigationProp>();
|
||||||
|
|
||||||
const handlePressTask = (taskId: string) => {
|
const handlePressTask = (taskId: string) => {
|
||||||
@ -28,7 +27,7 @@ export default function TaskListScreen() {
|
|||||||
renderItem={({ item }) => <TaskCard task={item} onPress={handlePressTask} />}
|
renderItem={({ item }) => <TaskCard task={item} onPress={handlePressTask} />}
|
||||||
keyExtractor={item => item.id}
|
keyExtractor={item => item.id}
|
||||||
numColumns={2}
|
numColumns={2}
|
||||||
columnWrapperStyle={styles.row}
|
contentContainerStyle={styles.list}
|
||||||
/>
|
/>
|
||||||
</View>
|
</View>
|
||||||
);
|
);
|
||||||
@ -37,9 +36,8 @@ export default function TaskListScreen() {
|
|||||||
const styles = StyleSheet.create({
|
const styles = StyleSheet.create({
|
||||||
container: {
|
container: {
|
||||||
flex: 1,
|
flex: 1,
|
||||||
backgroundColor: '#f5f5f5',
|
|
||||||
},
|
|
||||||
row: {
|
|
||||||
justifyContent: 'center',
|
|
||||||
},
|
},
|
||||||
|
list: {
|
||||||
|
padding: 8,
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
Loading…
x
Reference in New Issue
Block a user