webapp/src/components/TaskForm.tsx

191 lines
5.0 KiB
TypeScript
Raw Normal View History

import React, { useState, useRef, useEffect } from 'react';
import { StyleSheet, ScrollView, TouchableOpacity } from 'react-native';
import { Input, BottomSheet, ListItem } from '@rneui/themed';
import { Task, RobotAction } from '../types/task';
import { LOCATIONS, ROBOT_ACTIONS, PAYLOADS } from '../data/mockData';
interface TaskFormProps {
task: Task;
onTaskChange: (updatedTask: Task) => void;
onLocationBayChange?: (task: Task) => void; // 库位变化时的回调
}
const TaskForm: React.FC<TaskFormProps> = ({
task,
onTaskChange,
onLocationBayChange,
}) => {
const [isVisible, setIsVisible] = useState(false);
const [currentField, setCurrentField] = useState('');
const [currentItems, setCurrentItems] = useState<
{ label: string; value: string }[]
>([]);
// 创建库位输入框的ref
const locationBayInputRef = useRef<any>(null);
// 用于防抖的ref
const debounceTimerRef = useRef<NodeJS.Timeout | null>(null);
// 保存上一次的库位值,用于检测变化
const previousLocationBayRef = useRef<string>(
task.parameters.locationBay || '',
);
// 组件挂载时自动聚焦到库位输入框
useEffect(() => {
const timer = setTimeout(() => {
if (locationBayInputRef.current) {
locationBayInputRef.current.focus();
}
}, 100);
return () => clearTimeout(timer);
}, []);
// 监听库位值变化,自动触发运行任务
useEffect(() => {
const currentLocationBay = task.parameters.locationBay || '';
const previousLocationBay = previousLocationBayRef.current;
// 只有当库位值真正发生变化且不为空时才触发
if (
currentLocationBay !== previousLocationBay &&
currentLocationBay.trim() !== ''
) {
// 清除之前的防抖定时器
if (debounceTimerRef.current) {
clearTimeout(debounceTimerRef.current);
}
// 设置新的防抖定时器500ms后触发
debounceTimerRef.current = setTimeout(() => {
if (onLocationBayChange) {
onLocationBayChange(task);
}
}, 500);
}
// 更新上一次的库位值
previousLocationBayRef.current = currentLocationBay;
// 清理函数
return () => {
if (debounceTimerRef.current) {
clearTimeout(debounceTimerRef.current);
}
};
}, [task.parameters.locationBay, task, onLocationBayChange]);
const handleParamChange = (field: string, value: string | RobotAction) => {
const updatedTask = {
...task,
parameters: {
...task.parameters,
[field]: value,
},
};
onTaskChange(updatedTask);
};
const openBottomSheet = (
field: string,
items: { label: string; value: string }[],
) => {
setCurrentField(field);
setCurrentItems(items);
setIsVisible(true);
};
const renderDropdown = (
name: string,
label: string,
value: string,
items: { label: string; value: string }[],
) => (
<TouchableOpacity onPress={() => openBottomSheet(name, items)}>
<Input
label={label}
value={value}
editable={false}
rightIcon={{ name: 'arrow-drop-down' }}
/>
</TouchableOpacity>
);
return (
<ScrollView contentContainerStyle={styles.container}>
<Input
label="任务名称"
value={task.name}
onChangeText={text => onTaskChange({ ...task, name: text })}
/>
{renderDropdown(
'startLocation',
'起点',
task.parameters.startLocation,
LOCATIONS,
)}
{renderDropdown(
'endLocation',
'终点',
task.parameters.endLocation,
LOCATIONS,
)}
<Input
label="途经点 (可选)"
value={task.parameters.waypoint || ''}
onChangeText={text => handleParamChange('waypoint', text)}
/>
{renderDropdown(
'robotAction',
'机器人动作',
task.parameters.robotAction,
ROBOT_ACTIONS,
)}
{renderDropdown('payload', '载荷', task.parameters.payload, PAYLOADS)}
{/* 库位字段改为普通输入框 */}
<Input
ref={locationBayInputRef}
label="库位"
value={task.parameters.locationBay || ''}
onChangeText={text => handleParamChange('locationBay', text)}
showSoftInputOnFocus={false}
autoFocus={false}
placeholder="请输入库位"
/>
<BottomSheet
isVisible={isVisible}
onBackdropPress={() => setIsVisible(false)}
>
<ScrollView>
{currentItems.map((item, index) => (
<ListItem
key={index}
onPress={() => {
handleParamChange(currentField, item.value);
setIsVisible(false);
}}
>
<ListItem.Content>
<ListItem.Title>{item.label}</ListItem.Title>
</ListItem.Content>
</ListItem>
))}
</ScrollView>
</BottomSheet>
</ScrollView>
);
};
const styles = StyleSheet.create({
container: {
padding: 16,
},
});
export default TaskForm;