Commit acdc636e authored by fenghen777's avatar fenghen777

fix: WebSocket StrictMode竞态修复 + 项目面板输入框可划选文字

- useRosBridge: 增加manualDisconnectRef防护,防止StrictMode双重挂载导致无效重连
- ProjectPanel: 项目展开/重命名时禁用draggable,修复输入框无法划选文字
- ProjectPanel: HIL时长输入框支持清空
- ProjectPanel: expandedSection cursor:auto覆盖父级grab
- 清除所有诊断console.log
parent 5842d780
...@@ -263,8 +263,9 @@ export default function ProjectPanel() { ...@@ -263,8 +263,9 @@ export default function ProjectPanel() {
dragOver?.index === index && dragOver?.position === 'above' ? styles.dragOverAbove : '', dragOver?.index === index && dragOver?.position === 'above' ? styles.dragOverAbove : '',
dragOver?.index === index && dragOver?.position === 'below' ? styles.dragOverBelow : '', dragOver?.index === index && dragOver?.position === 'below' ? styles.dragOverBelow : '',
].filter(Boolean).join(' ')} ].filter(Boolean).join(' ')}
draggable draggable={!isActive && renamingId !== p.id}
onDragStart={(e) => { onDragStart={(e) => {
if (isActive || renamingId === p.id) { e.preventDefault(); return; }
dragIndexRef.current = index; dragIndexRef.current = index;
e.dataTransfer.effectAllowed = 'move'; e.dataTransfer.effectAllowed = 'move';
e.currentTarget.style.opacity = '0.4'; e.currentTarget.style.opacity = '0.4';
...@@ -488,7 +489,8 @@ export default function ProjectPanel() { ...@@ -488,7 +489,8 @@ export default function ProjectPanel() {
type="number" type="number"
min="1" max="3600" step="1" min="1" max="3600" step="1"
value={hilDuration} value={hilDuration}
onChange={(e) => setHilDuration(Number(e.target.value) || 10)} onChange={(e) => setHilDuration(e.target.value === '' ? '' : Number(e.target.value))}
onBlur={() => { if (!hilDuration || hilDuration <= 0) setHilDuration(10); }}
onClick={(e) => e.stopPropagation()} onClick={(e) => e.stopPropagation()}
disabled={hilDisabled} disabled={hilDisabled}
style={{ style={{
......
...@@ -166,6 +166,7 @@ ...@@ -166,6 +166,7 @@
padding: 8px 12px 12px; padding: 8px 12px 12px;
border-top: 1px solid rgba(99, 102, 241, 0.15); border-top: 1px solid rgba(99, 102, 241, 0.15);
background: rgba(99, 102, 241, 0.03); background: rgba(99, 102, 241, 0.03);
cursor: auto;
} }
.statusRow { .statusRow {
......
...@@ -10,6 +10,9 @@ ...@@ -10,6 +10,9 @@
* /hil/done — 仿真完成信号 * /hil/done — 仿真完成信号
* *
* 自动重连: 连接失败或断开后自动重试 (最多 MAX_RETRIES 次, 间隔 RETRY_DELAY_MS) * 自动重连: 连接失败或断开后自动重试 (最多 MAX_RETRIES 次, 间隔 RETRY_DELAY_MS)
*
* StrictMode 安全: 使用 mountedRef 防止 React 开发模式双重挂载时
* 第一次挂载的 WebSocket 在 cleanup 后仍然触发 onclose 重连。
*/ */
import { useState, useRef, useCallback, useEffect } from 'react'; import { useState, useRef, useCallback, useEffect } from 'react';
...@@ -45,17 +48,22 @@ export default function useRosBridge({ onDone } = {}) { ...@@ -45,17 +48,22 @@ export default function useRosBridge({ onDone } = {}) {
}, []); }, []);
const connectInternal = useCallback((url) => { const connectInternal = useCallback((url) => {
// 如果已被手动断开(包括 StrictMode cleanup),不再尝试连接
if (manualDisconnectRef.current) return;
if (wsRef.current) return; if (wsRef.current) return;
console.log('[RosBridge] connecting to', url, 'attempt', retryCountRef.current);
setStatus('connecting'); setStatus('connecting');
const ws = new WebSocket(url); const ws = new WebSocket(url);
wsRef.current = ws; wsRef.current = ws;
ws.onopen = () => { ws.onopen = () => {
console.log('[RosBridge] connected!'); // 连接成功后再次检查,防止 StrictMode cleanup 已在 open 之前触发
if (manualDisconnectRef.current) {
ws.close();
return;
}
setStatus('connected'); setStatus('connected');
retryCountRef.current = 0; // 连接成功, 重置重试计数 retryCountRef.current = 0;
// 订阅仿真数据 // 订阅仿真数据
ws.send(JSON.stringify({ ws.send(JSON.stringify({
op: 'subscribe', op: 'subscribe',
...@@ -98,14 +106,12 @@ export default function useRosBridge({ onDone } = {}) { ...@@ -98,14 +106,12 @@ export default function useRosBridge({ onDone } = {}) {
flushToState(); flushToState();
} }
} catch (e) { } catch {
// 忽略 // 忽略解析错误
} }
}; };
ws.onerror = (e) => { ws.onerror = () => {};
console.warn('[RosBridge] error', e);
};
ws.onclose = () => { ws.onclose = () => {
wsRef.current = null; wsRef.current = null;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment