diff --git a/src/components/TaskForm.tsx b/src/components/TaskForm.tsx index bc3e3bc..f01e4da 100644 --- a/src/components/TaskForm.tsx +++ b/src/components/TaskForm.tsx @@ -1,81 +1,152 @@ import React, { useState, useRef, useEffect } from 'react'; -import { StyleSheet, ScrollView, TouchableOpacity } from 'react-native'; -import { Input, BottomSheet, ListItem } from '@rneui/themed'; +import { StyleSheet, ScrollView, TouchableOpacity, View } from 'react-native'; +import { Input, BottomSheet, ListItem, Button } 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 = ({ - task, - onTaskChange, - onLocationBayChange, -}) => { +const TaskForm: React.FC = ({ task, onTaskChange }) => { const [isVisible, setIsVisible] = useState(false); const [currentField, setCurrentField] = useState(''); const [currentItems, setCurrentItems] = useState< { label: string; value: string }[] >([]); + const [isQrInputFocused, setIsQrInputFocused] = useState(true); - // 创建库位输入框的ref - const locationBayInputRef = useRef(null); - // 用于防抖的ref - const debounceTimerRef = useRef(null); - // 保存上一次的库位值,用于检测变化 - const previousLocationBayRef = useRef( - task.parameters.locationBay || '', - ); + // 创建隐藏的二维码扫描输入框的ref + const qrScanInputRef = useRef(null); - // 组件挂载时自动聚焦到库位输入框 + // 用于防止循环更新的标志 + const isUpdatingFromQrRef = useRef(false); + const isUpdatingFromFormRef = useRef(false); + + // 组件挂载时自动聚焦到隐藏的扫描输入框 useEffect(() => { const timer = setTimeout(() => { - if (locationBayInputRef.current) { - locationBayInputRef.current.focus(); + if (qrScanInputRef.current) { + qrScanInputRef.current.focus(); } }, 100); return () => clearTimeout(timer); }, []); - // 监听库位值变化,自动触发运行任务 - useEffect(() => { - const currentLocationBay = task.parameters.locationBay || ''; - const previousLocationBay = previousLocationBayRef.current; + // 解析二维码信息对象字面量格式 + const parseQrCodeInfo = (infoString: string): Partial => { + const result: Partial = {}; - // 只有当库位值真正发生变化且不为空时才触发 - if ( - currentLocationBay !== previousLocationBay && - currentLocationBay.trim() !== '' - ) { - // 清除之前的防抖定时器 - if (debounceTimerRef.current) { - clearTimeout(debounceTimerRef.current); + try { + // 移除花括号和换行符,准备解析 + let cleanString = infoString.trim(); + if (cleanString.startsWith('{')) { + cleanString = cleanString.substring(1); + } + if (cleanString.endsWith('}')) { + cleanString = cleanString.substring(0, cleanString.length - 1); } - // 设置新的防抖定时器,500ms后触发 - debounceTimerRef.current = setTimeout(() => { - if (onLocationBayChange) { - onLocationBayChange(task); + // 按逗号分割各个属性 + const items = cleanString.split(','); + + for (const item of items) { + const trimmedItem = item.trim(); + if (!trimmedItem) continue; + + // 解析 "key: value" 格式 + const colonIndex = trimmedItem.indexOf(':'); + if (colonIndex === -1) continue; + + const key = trimmedItem.substring(0, colonIndex).trim(); + const value = trimmedItem.substring(colonIndex + 1).trim(); + + // 映射字段名 + switch (key) { + case 'startLocation': + result.startLocation = value; + break; + case 'endLocation': + result.endLocation = value; + break; + case 'waypoint': + result.waypoint = value; + break; + case 'robotAction': + result.robotAction = value as RobotAction; + break; + case 'payload': + result.payload = value; + break; + case 'locationBay': + result.locationBay = value; + break; } - }, 500); + } + } catch (error) { + // 解析失败时不报错,返回空对象 + console.log('解析二维码信息失败:', error); } - // 更新上一次的库位值 - previousLocationBayRef.current = currentLocationBay; + return result; + }; - // 清理函数 - return () => { - if (debounceTimerRef.current) { - clearTimeout(debounceTimerRef.current); - } + // 处理二维码扫描输入,更新表单字段 + const handleQrCodeScan = (scanData: string) => { + if (isUpdatingFromFormRef.current || !scanData.trim()) return; + + isUpdatingFromQrRef.current = true; + const parsedParams = parseQrCodeInfo(scanData); + + const updatedTask = { + ...task, + parameters: { + ...task.parameters, + ...parsedParams, + }, }; - }, [task.parameters.locationBay, task, onLocationBayChange]); + + onTaskChange(updatedTask); + + // 清空扫描输入框 + if (qrScanInputRef.current) { + qrScanInputRef.current.clear(); + } + + // 重置标志 + setTimeout(() => { + isUpdatingFromQrRef.current = false; + }, 0); + }; + + // 重新扫描按钮点击处理 + const handleRescan = () => { + if (qrScanInputRef.current) { + qrScanInputRef.current.focus(); + } + }; + + // 处理其他输入框获得焦点 + const handleOtherInputFocus = () => { + setIsQrInputFocused(false); + }; + + // 处理二维码输入框焦点事件 + const handleQrInputFocus = () => { + setIsQrInputFocused(true); + }; + + const handleQrInputBlur = () => { + setIsQrInputFocused(false); + }; const handleParamChange = (field: string, value: string | RobotAction) => { + if (isUpdatingFromQrRef.current) return; + + isUpdatingFromFormRef.current = true; + const updatedTask = { ...task, parameters: { @@ -84,6 +155,11 @@ const TaskForm: React.FC = ({ }, }; onTaskChange(updatedTask); + + // 重置标志 + setTimeout(() => { + isUpdatingFromFormRef.current = false; + }, 0); }; const openBottomSheet = ( @@ -113,10 +189,43 @@ const TaskForm: React.FC = ({ return ( + {/* 隐藏的二维码扫描输入框 */} + + + {/* 扫描二维码按钮 */} + +