删除连线操作

This commit is contained in:
YHH
2025-06-18 15:43:17 +08:00
parent 96f651b7ca
commit 92125aee3a
4 changed files with 83 additions and 6 deletions

View File

@@ -303,6 +303,27 @@ export function useBehaviorTreeEditor() {
alert(message); alert(message);
}; };
// 清除所有连接线
const clearAllConnections = () => {
if (appState.connections.value.length === 0) {
alert('当前没有连接线需要清除!');
return;
}
if (confirm(`确定要清除所有 ${appState.connections.value.length} 条连接线吗?此操作不可撤销。`)) {
// 清除所有节点的父子关系
appState.treeNodes.value.forEach(node => {
node.parent = undefined;
node.children = [];
});
// 清空连接数组
appState.connections.value = [];
alert('已清除所有连接线!');
}
};
onMounted(() => { onMounted(() => {
const appContainer = document.querySelector('#behavior-tree-app'); const appContainer = document.querySelector('#behavior-tree-app');
if (appContainer) { if (appContainer) {
@@ -321,15 +342,28 @@ export function useBehaviorTreeEditor() {
alert('文件加载失败: ' + event.detail.error); alert('文件加载失败: ' + event.detail.error);
}; };
// 键盘快捷键处理
const handleKeydown = (event: KeyboardEvent) => {
// Delete键删除选中的节点
if (event.key === 'Delete' && appState.selectedNodeId.value) {
event.preventDefault();
nodeOps.deleteNode(appState.selectedNodeId.value);
}
// Escape键取消连接
if (event.key === 'Escape' && connectionState.isConnecting) {
event.preventDefault();
connectionManager.cancelConnection();
}
};
document.addEventListener('load-behavior-tree-file', handleLoadBehaviorTreeFile as EventListener); document.addEventListener('load-behavior-tree-file', handleLoadBehaviorTreeFile as EventListener);
document.addEventListener('file-load-error', handleFileLoadError as EventListener); document.addEventListener('file-load-error', handleFileLoadError as EventListener);
document.addEventListener('keydown', handleKeydown);
console.log('[BehaviorTreeEditor] 事件系统准备完成(直接方法调用 + DOM事件备用');
onUnmounted(() => { onUnmounted(() => {
console.log('[BehaviorTreeEditor] 清理事件监听器');
document.removeEventListener('load-behavior-tree-file', handleLoadBehaviorTreeFile as EventListener); document.removeEventListener('load-behavior-tree-file', handleLoadBehaviorTreeFile as EventListener);
document.removeEventListener('file-load-error', handleFileLoadError as EventListener); document.removeEventListener('file-load-error', handleFileLoadError as EventListener);
document.removeEventListener('keydown', handleKeydown);
// 清理暴露的方法 // 清理暴露的方法
if (appContainer) { if (appContainer) {
@@ -361,6 +395,7 @@ export function useBehaviorTreeEditor() {
startNodeDrag, startNodeDrag,
dragState, dragState,
autoLayout, autoLayout,
validateTree validateTree,
clearAllConnections
}; };
} }

View File

@@ -473,11 +473,47 @@ export function useConnectionManager(
}, 50); // 50ms延迟确保DOM渲染完成 }, 50); // 50ms延迟确保DOM渲染完成
}; };
// 删除连接线
const removeConnection = (connectionId: string) => {
const connection = connections.value.find(conn => conn.id === connectionId);
if (!connection) return;
const parentNode = treeNodes.value.find(n => n.id === connection.sourceId);
const childNode = treeNodes.value.find(n => n.id === connection.targetId);
if (parentNode && childNode) {
// 从父节点的children中移除
const index = parentNode.children.indexOf(connection.targetId);
if (index > -1) {
parentNode.children.splice(index, 1);
}
// 清除子节点的parent
childNode.parent = undefined;
// 更新连接线
updateConnections();
}
};
// 连接线点击事件处理
const onConnectionClick = (event: MouseEvent, connectionId: string) => {
event.preventDefault();
event.stopPropagation();
// 询问用户是否要删除连接
if (confirm('确定要删除这条连接线吗?')) {
removeConnection(connectionId);
}
};
return { return {
getPortPosition, getPortPosition,
startConnection, startConnection,
cancelConnection, cancelConnection,
updateConnections, updateConnections,
removeConnection,
onConnectionClick,
onPortHover, onPortHover,
onPortLeave, onPortLeave,
isValidConnectionTarget isValidConnectionTarget

View File

@@ -281,12 +281,15 @@
transition: none; transition: none;
opacity: 0.9; opacity: 0.9;
will-change: d; will-change: d;
pointer-events: stroke;
cursor: pointer;
} }
.connection-line:hover { .connection-line:hover {
stroke: #9f7aea; stroke: #f56565;
stroke-width: 4; stroke-width: 5;
opacity: 1; opacity: 1;
filter: drop-shadow(0 0 4px rgba(245, 101, 101, 0.6));
} }
.connection-active { .connection-active {

View File

@@ -152,6 +152,7 @@
<button @click="centerView">居中</button> <button @click="centerView">居中</button>
<button @click="autoLayout">自动布局</button> <button @click="autoLayout">自动布局</button>
<button @click="validateTree">验证</button> <button @click="validateTree">验证</button>
<button @click="clearAllConnections" title="清除所有连接线" v-if="connections.length > 0">清除连线</button>
</div> </div>
</div> </div>
@@ -186,6 +187,8 @@
:d="connection.path" :d="connection.path"
class="connection-line" class="connection-line"
:class="{ 'connection-active': connection.active }" :class="{ 'connection-active': connection.active }"
@click="onConnectionClick($event, connection.id)"
:title="'点击删除连接线 (' + connection.sourceId + ' → ' + connection.targetId + ')'"
/> />
<!-- 临时连接线 --> <!-- 临时连接线 -->
<path <path