feat: 添加库位输入框及变化监听,自动运行任务
This commit is contained in:
parent
02a326e60e
commit
726b7db95f
@ -1,26 +1,80 @@
|
||||
import React, { useState } from 'react';
|
||||
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,
|
||||
LOCATIONS_BAYS,
|
||||
} from '../data/mockData';
|
||||
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 }) => {
|
||||
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,
|
||||
@ -91,12 +145,17 @@ const TaskForm: React.FC<TaskFormProps> = ({ task, onTaskChange }) => {
|
||||
ROBOT_ACTIONS,
|
||||
)}
|
||||
{renderDropdown('payload', '载荷', task.parameters.payload, PAYLOADS)}
|
||||
{renderDropdown(
|
||||
'locationBay',
|
||||
'库位',
|
||||
task.parameters.locationBay || '',
|
||||
LOCATIONS_BAYS,
|
||||
)}
|
||||
|
||||
{/* 库位字段改为普通输入框 */}
|
||||
<Input
|
||||
ref={locationBayInputRef}
|
||||
label="库位"
|
||||
value={task.parameters.locationBay || ''}
|
||||
onChangeText={text => handleParamChange('locationBay', text)}
|
||||
showSoftInputOnFocus={false}
|
||||
autoFocus={false}
|
||||
placeholder="请输入库位"
|
||||
/>
|
||||
|
||||
<BottomSheet
|
||||
isVisible={isVisible}
|
||||
|
@ -2,8 +2,8 @@ import { Task, RobotAction } from '../types/task';
|
||||
import { v4 as uuidv4 } from 'uuid';
|
||||
|
||||
export const LOCATIONS = Array.from({ length: 100 }, (_, i) => ({
|
||||
label: `AP-${i + 1}`,
|
||||
value: `AP-${i + 1}`,
|
||||
label: `AP-${i + 1}`,
|
||||
value: `AP-${i + 1}`,
|
||||
}));
|
||||
|
||||
export const ROBOT_ACTIONS: { label: string; value: RobotAction }[] = [
|
||||
@ -16,38 +16,48 @@ export const ROBOT_ACTIONS: { label: string; value: RobotAction }[] = [
|
||||
];
|
||||
|
||||
export const LOCATIONS_BAYS = Array.from({ length: 100 }, (_, i) => ({
|
||||
label: `AS2_2_${String(i + 1).padStart(3, '0')}`,
|
||||
value: `AS2_2_${String(i + 1).padStart(3, '0')}`,
|
||||
label: `AS2_2_${String(i + 1).padStart(3, '0')}`,
|
||||
value: `AS2_2_${String(i + 1).padStart(3, '0')}`,
|
||||
}));
|
||||
|
||||
export const PAYLOADS = [
|
||||
{ label: '满料架-A1', value: '满料架-A1' },
|
||||
{ label: '空料架-B2', value: '空料架-B2' },
|
||||
{ label: '空料架-C3', value: '空料架-C3' },
|
||||
{ label: '空车', value: '空车' },
|
||||
{ label: '满料架-A1', value: '满料架-A1' },
|
||||
{ label: '空料架-B2', value: '空料架-B2' },
|
||||
{ label: '空料架-C3', value: '空料架-C3' },
|
||||
{ label: '空车', value: '空车' },
|
||||
];
|
||||
|
||||
const getRandomElement = <T>(arr: T[]): T => arr[Math.floor(Math.random() * arr.length)];
|
||||
const getRandomElement = <T>(arr: T[]): T =>
|
||||
arr[Math.floor(Math.random() * arr.length)];
|
||||
|
||||
export const MOCK_TASKS: Task[] = Array.from({ length: 15 }, (_, i) => {
|
||||
const startLocation = getRandomElement(LOCATIONS);
|
||||
const endLocation = getRandomElement(LOCATIONS.filter(l => l.value !== startLocation.value));
|
||||
const robotAction = getRandomElement(ROBOT_ACTIONS);
|
||||
const payload = getRandomElement(PAYLOADS);
|
||||
const statusOptions: Task['status'][] = ['IDLE', 'RUNNING', 'COMPLETED', 'ERROR'];
|
||||
const status = getRandomElement(statusOptions);
|
||||
const startLocation = getRandomElement(LOCATIONS);
|
||||
const endLocation = getRandomElement(
|
||||
LOCATIONS.filter(l => l.value !== startLocation.value),
|
||||
);
|
||||
const robotAction = getRandomElement(ROBOT_ACTIONS);
|
||||
const payload = getRandomElement(PAYLOADS);
|
||||
const statusOptions: Task['status'][] = [
|
||||
'IDLE',
|
||||
'RUNNING',
|
||||
'COMPLETED',
|
||||
'ERROR',
|
||||
];
|
||||
const status = getRandomElement(statusOptions);
|
||||
|
||||
return {
|
||||
id: uuidv4(),
|
||||
name: `任务 ${i + 1}: 从 ${startLocation.label} 到 ${endLocation.label}`,
|
||||
status: status,
|
||||
createdAt: new Date(new Date().getTime() - Math.random() * 1000 * 60 * 60 * 24).toISOString(),
|
||||
parameters: {
|
||||
startLocation: startLocation.value,
|
||||
endLocation: endLocation.value,
|
||||
robotAction: robotAction.value,
|
||||
payload: payload.value,
|
||||
locationBay: getRandomElement(LOCATIONS_BAYS).value,
|
||||
},
|
||||
};
|
||||
return {
|
||||
id: uuidv4(),
|
||||
name: `任务 ${i + 1}: 从 ${startLocation.label} 到 ${endLocation.label}`,
|
||||
status: status,
|
||||
createdAt: new Date(
|
||||
new Date().getTime() - Math.random() * 1000 * 60 * 60 * 24,
|
||||
).toISOString(),
|
||||
parameters: {
|
||||
startLocation: startLocation.value,
|
||||
endLocation: endLocation.value,
|
||||
robotAction: robotAction.value,
|
||||
payload: payload.value,
|
||||
locationBay: '', // 库位初始值为空
|
||||
},
|
||||
};
|
||||
});
|
||||
|
@ -32,7 +32,6 @@ export default function TaskEditScreen() {
|
||||
}
|
||||
}, [initialTask]);
|
||||
|
||||
|
||||
const handleTaskChange = (updatedTask: Task) => {
|
||||
setTask(updatedTask);
|
||||
if (!isModified) {
|
||||
@ -48,35 +47,48 @@ export default function TaskEditScreen() {
|
||||
Alert.alert('已保存', `任务 "${task.name}" 已被保存。`);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
const handleRun = () => {
|
||||
if(task) {
|
||||
runTask(task.id);
|
||||
navigation.goBack();
|
||||
if (task) {
|
||||
runTask(task.id);
|
||||
navigation.goBack();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const handleUndo = () => {
|
||||
setTask(originalTask);
|
||||
setIsModified(false);
|
||||
}
|
||||
setTask(originalTask);
|
||||
setIsModified(false);
|
||||
};
|
||||
|
||||
const handleRestore = () => {
|
||||
setTask(originalTask);
|
||||
setIsModified(false);
|
||||
}
|
||||
};
|
||||
|
||||
// 处理库位变化,自动运行任务
|
||||
const handleLocationBayChange = (updatedTask: Task) => {
|
||||
console.log(
|
||||
'库位已变化,自动运行任务:',
|
||||
updatedTask.parameters.locationBay,
|
||||
);
|
||||
runTask(updatedTask.id);
|
||||
};
|
||||
|
||||
if (!task) {
|
||||
return (
|
||||
<Dialog isVisible={true}>
|
||||
<Dialog.Loading />
|
||||
</Dialog>
|
||||
<Dialog isVisible={true}>
|
||||
<Dialog.Loading />
|
||||
</Dialog>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<View style={styles.container}>
|
||||
<TaskForm task={task} onTaskChange={handleTaskChange} />
|
||||
<TaskForm
|
||||
task={task}
|
||||
onTaskChange={handleTaskChange}
|
||||
onLocationBayChange={handleLocationBayChange}
|
||||
/>
|
||||
<BottomActionBar
|
||||
onRun={handleRun}
|
||||
onSave={handleSave}
|
||||
|
@ -1,5 +1,11 @@
|
||||
// 机器人的具体动作,可以定义为枚举或联合类型
|
||||
export type RobotAction = 'PICKUP' | 'DROPOFF' | 'TRANSPORT' | 'WAIT';
|
||||
export type RobotAction =
|
||||
| 'PICKUP'
|
||||
| 'DROPOFF'
|
||||
| 'TRANSPORT'
|
||||
| 'WAIT'
|
||||
| 'CHARGE'
|
||||
| 'CLEAN';
|
||||
|
||||
// 任务的状态
|
||||
export type TaskStatus = 'IDLE' | 'RUNNING' | 'COMPLETED' | 'ERROR';
|
||||
@ -7,11 +13,11 @@ export type TaskStatus = 'IDLE' | 'RUNNING' | 'COMPLETED' | 'ERROR';
|
||||
// 任务参数
|
||||
export interface TaskParameters {
|
||||
startLocation: string; // 起点
|
||||
endLocation: string; // 终点
|
||||
waypoint?: string; // 途经点 (可选)
|
||||
endLocation: string; // 终点
|
||||
waypoint?: string; // 途经点 (可选)
|
||||
robotAction: RobotAction; // 机器人动作
|
||||
payload: string; // 载荷,比如 '空料架' 或具体的物料ID
|
||||
locationBay?: string; // 库位 (可选)
|
||||
payload: string; // 载荷,比如 '空料架' 或具体的物料ID
|
||||
locationBay?: string; // 库位 (可选)
|
||||
}
|
||||
|
||||
// 核心任务对象
|
||||
|
Loading…
x
Reference in New Issue
Block a user