2025-07-22 11:16:39 +08:00
|
|
|
|
import React, { useState, useRef, useEffect } from 'react';
|
2025-07-21 19:03:11 +08:00
|
|
|
|
import { StyleSheet, ScrollView, TouchableOpacity } from 'react-native';
|
|
|
|
|
import { Input, BottomSheet, ListItem } from '@rneui/themed';
|
2025-07-21 15:10:39 +08:00
|
|
|
|
import { Task, RobotAction } from '../types/task';
|
2025-07-22 11:16:39 +08:00
|
|
|
|
import { LOCATIONS, ROBOT_ACTIONS, PAYLOADS } from '../data/mockData';
|
2025-07-21 15:10:39 +08:00
|
|
|
|
|
|
|
|
|
interface TaskFormProps {
|
|
|
|
|
task: Task;
|
|
|
|
|
onTaskChange: (updatedTask: Task) => void;
|
2025-07-22 11:16:39 +08:00
|
|
|
|
onLocationBayChange?: (task: Task) => void; // 库位变化时的回调
|
2025-07-21 15:10:39 +08:00
|
|
|
|
}
|
|
|
|
|
|
2025-07-22 11:16:39 +08:00
|
|
|
|
const TaskForm: React.FC<TaskFormProps> = ({
|
|
|
|
|
task,
|
|
|
|
|
onTaskChange,
|
|
|
|
|
onLocationBayChange,
|
|
|
|
|
}) => {
|
2025-07-21 16:45:09 +08:00
|
|
|
|
const [isVisible, setIsVisible] = useState(false);
|
|
|
|
|
const [currentField, setCurrentField] = useState('');
|
|
|
|
|
const [currentItems, setCurrentItems] = useState<
|
|
|
|
|
{ label: string; value: string }[]
|
|
|
|
|
>([]);
|
2025-07-21 15:36:11 +08:00
|
|
|
|
|
2025-07-22 11:16:39 +08:00
|
|
|
|
// 创建库位输入框的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]);
|
|
|
|
|
|
2025-07-21 16:45:09 +08:00
|
|
|
|
const handleParamChange = (field: string, value: string | RobotAction) => {
|
|
|
|
|
const updatedTask = {
|
|
|
|
|
...task,
|
|
|
|
|
parameters: {
|
|
|
|
|
...task.parameters,
|
|
|
|
|
[field]: value,
|
|
|
|
|
},
|
2025-07-21 15:10:39 +08:00
|
|
|
|
};
|
2025-07-21 16:45:09 +08:00
|
|
|
|
onTaskChange(updatedTask);
|
|
|
|
|
};
|
2025-07-21 15:10:39 +08:00
|
|
|
|
|
2025-07-21 16:45:09 +08:00
|
|
|
|
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>
|
|
|
|
|
);
|
2025-07-21 15:10:39 +08:00
|
|
|
|
|
2025-07-21 16:45:09 +08:00
|
|
|
|
return (
|
|
|
|
|
<ScrollView contentContainerStyle={styles.container}>
|
|
|
|
|
<Input
|
|
|
|
|
label="任务名称"
|
|
|
|
|
value={task.name}
|
|
|
|
|
onChangeText={text => onTaskChange({ ...task, name: text })}
|
|
|
|
|
/>
|
2025-07-21 15:10:39 +08:00
|
|
|
|
|
2025-07-21 16:45:09 +08:00
|
|
|
|
{renderDropdown(
|
|
|
|
|
'startLocation',
|
|
|
|
|
'起点',
|
|
|
|
|
task.parameters.startLocation,
|
|
|
|
|
LOCATIONS,
|
|
|
|
|
)}
|
|
|
|
|
{renderDropdown(
|
|
|
|
|
'endLocation',
|
|
|
|
|
'终点',
|
|
|
|
|
task.parameters.endLocation,
|
|
|
|
|
LOCATIONS,
|
|
|
|
|
)}
|
2025-07-21 15:36:11 +08:00
|
|
|
|
|
2025-07-21 16:45:09 +08:00
|
|
|
|
<Input
|
|
|
|
|
label="途经点 (可选)"
|
|
|
|
|
value={task.parameters.waypoint || ''}
|
|
|
|
|
onChangeText={text => handleParamChange('waypoint', text)}
|
|
|
|
|
/>
|
|
|
|
|
|
|
|
|
|
{renderDropdown(
|
|
|
|
|
'robotAction',
|
|
|
|
|
'机器人动作',
|
|
|
|
|
task.parameters.robotAction,
|
|
|
|
|
ROBOT_ACTIONS,
|
|
|
|
|
)}
|
|
|
|
|
{renderDropdown('payload', '载荷', task.parameters.payload, PAYLOADS)}
|
2025-07-22 11:16:39 +08:00
|
|
|
|
|
|
|
|
|
{/* 库位字段改为普通输入框 */}
|
|
|
|
|
<Input
|
|
|
|
|
ref={locationBayInputRef}
|
|
|
|
|
label="库位"
|
|
|
|
|
value={task.parameters.locationBay || ''}
|
|
|
|
|
onChangeText={text => handleParamChange('locationBay', text)}
|
|
|
|
|
showSoftInputOnFocus={false}
|
|
|
|
|
autoFocus={false}
|
|
|
|
|
placeholder="请输入库位"
|
|
|
|
|
/>
|
2025-07-21 16:45:09 +08:00
|
|
|
|
|
|
|
|
|
<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>
|
|
|
|
|
))}
|
2025-07-21 15:59:44 +08:00
|
|
|
|
</ScrollView>
|
2025-07-21 16:45:09 +08:00
|
|
|
|
</BottomSheet>
|
|
|
|
|
</ScrollView>
|
|
|
|
|
);
|
2025-07-21 15:10:39 +08:00
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
const styles = StyleSheet.create({
|
2025-07-21 16:45:09 +08:00
|
|
|
|
container: {
|
|
|
|
|
padding: 16,
|
|
|
|
|
},
|
2025-07-21 15:10:39 +08:00
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
export default TaskForm;
|