Jelajahi Sumber

pref: 优化节点逻辑

jiaxing.liao 1 bulan lalu
induk
melakukan
0a35159b08

+ 2 - 0
packages/workflow/src/components/Canvas.vue

@@ -403,6 +403,8 @@ defineExpose({
 					:node="nodeById[nodeProps.id]!"
 					:read-only="readOnly"
 					:hovered="nodesHoveredById[nodeProps.id]"
+					@click:node="(id, position) => emit('click:node', id, position)"
+					@dblclick:node="(id, position) => emit('dblclick:node', id, position)"
 					@move="onUpdateNodePosition"
 					@update="onUpdateNodeAttrs"
 					@add-node="

+ 1 - 2
packages/workflow/src/components/elements/handles/HandlePort.vue

@@ -52,7 +52,7 @@ const onAdd = (event: MouseEvent) => {
 				@mouseenter="onMouseEnter"
 				@mouseleave="onMouseLeave"
 			>
-				<line x1="0" y1="12" x2="18" y2="12" class="handleAddAction__line" stroke-width="2" />
+				<line x1="0" y1="12" x2="21" y2="12" class="handleAddAction__line" stroke-width="2" />
 				<g
 					data-test-id="canvas-handle-plus"
 					class="handleAddAction__plus clickable"
@@ -89,7 +89,6 @@ const onAdd = (event: MouseEvent) => {
 .handleAddAction {
 	width: 44px;
 	height: 24px;
-	margin-left: 4px;
 	flex-shrink: 0;
 	overflow: visible;
 	pointer-events: none;

+ 4 - 0
packages/workflow/src/components/elements/nodes/CanvasNode.vue

@@ -32,6 +32,8 @@ const emit = defineEmits<{
 	move: [id: string, position: { x: number; y: number }]
 	delete: [id: string]
 	run: [id: string]
+	'click:node': [id: string, position: XYPosition]
+	'dblclick:node': [id: string, position: XYPosition]
 	'add-node': [payload: { nodeId: string; handleId: string; event: MouseEvent }]
 	'add-inner-node': []
 	'add-inner-edge': [connection: Connection]
@@ -159,6 +161,8 @@ provideCanvasNodeContext({
 		<NodeRenderer
 			v-bind="$attrs"
 			@update="onUpdate"
+			@click:node="(id, position) => emit('click:node', id, position)"
+			@dblclick:node="(id, position) => emit('dblclick:node', id, position)"
 			@click:node:add="emit('add-node', $event)"
 			@add-inner-node="emit('add-inner-node')"
 			@add-inner-edge="emit('add-inner-edge', $event)"

+ 51 - 52
packages/workflow/src/components/elements/nodes/CanvasNodeToolBar.vue

@@ -17,9 +17,7 @@ const props = defineProps<{
 const node = useCanvasNodeContext()
 
 const barState = ref(false)
-const more = () => {
-	barState.value = !barState.value
-}
+
 const BarHandleClick = (state: string) => {
 	barState.value = false
 	if (state === 'node-run') {
@@ -51,7 +49,9 @@ watch(
 	{ immediate: true }
 )
 
-const renderToolbar = computed(() => delayedHovered.value && !node.props.value.readOnly)
+const renderToolbar = computed(
+	() => (delayedHovered.value && !node.props.value.readOnly) || barState.value
+)
 </script>
 
 <template>
@@ -64,60 +64,59 @@ const renderToolbar = computed(() => delayedHovered.value && !node.props.value.r
 				class="text-gray-400 p-2 hover:cursor-pointer hover:bg-gray-200"
 				@click="BarHandleClick('node-run')"
 			/>
-			<Icon
-				icon="lucide:ellipsis"
-				width="12"
-				height="12"
-				class="text-gray-400 p-2 hover:cursor-pointer hover:bg-gray-200"
-				@click.stop="more"
-			/>
-		</div>
-		<div
-			class="modal absolute -right-26 z-100 bg-white rounded-lg shadow-xl shadow-gray-200"
-			v-show="barState"
-		>
-			<ul class="text-sm">
-				<li @click.stop="BarHandleClick('node-run')">
-					<p>运行此步骤</p>
-				</li>
-				<li @click.stop="BarHandleClick('node-edit')">
-					<p>更改节点</p>
-				</li>
-				<li @click.stop="BarHandleClick('node-copy')">
-					<p>拷贝</p>
-				</li>
-				<li @click.stop="onDelete">
-					<p>删除</p>
-				</li>
-				<li @click.stop="BarHandleClick('node-doc')">
-					<p>查看文档</p>
-				</li>
-			</ul>
+			<el-popover v-model:visible="barState" trigger="click" width="240px">
+				<template #reference>
+					<Icon
+						icon="lucide:ellipsis"
+						width="12"
+						height="12"
+						class="text-gray-400 p-2 hover:cursor-pointer hover:bg-gray-200"
+					/>
+				</template>
+				<div class="modal flex flex-col">
+					<ul class="text-sm">
+						<li @click.stop="BarHandleClick('node-run')">
+							<p>运行此步骤</p>
+						</li>
+						<li @click.stop="BarHandleClick('node-edit')">
+							<p>更改节点</p>
+						</li>
+						<li @click.stop="BarHandleClick('node-copy')">
+							<p>拷贝</p>
+						</li>
+						<li @click.stop="onDelete">
+							<p>删除</p>
+						</li>
+						<li @click.stop="BarHandleClick('node-doc')">
+							<p>查看文档</p>
+						</li>
+					</ul>
+				</div>
+			</el-popover>
 		</div>
 	</div>
 </template>
 
 <style scoped lang="less">
-.node-tools {
-	.modal {
-		width: 240px;
-		ul {
+.modal {
+	ul {
+		margin: 0;
+		padding: 0;
+	}
+	li {
+		padding: 6px;
+		text-align: left;
+		list-style: none;
+		border-bottom: 1px solid #eee;
+		margin: 0;
+		box-sizing: border-box;
+		p {
 			margin: 0;
-			padding: 0;
-		}
-		li {
-			padding: 6px;
-			text-align: left;
-			list-style: none;
-			border-bottom: 1px solid #eee;
-			p {
-				margin: 0;
-				padding: 10px 20px;
-				border-radius: 12px;
-				&:hover {
-					cursor: pointer;
-					background: #e5eff6;
-				}
+			padding: 10px 20px;
+			border-radius: 12px;
+			&:hover {
+				cursor: pointer;
+				background: #e5eff6;
 			}
 		}
 	}

+ 15 - 5
packages/workflow/src/components/elements/nodes/render-types/NodeLoop.vue

@@ -1,5 +1,5 @@
 <script setup lang="ts">
-import { computed } from 'vue'
+import { computed, ref } from 'vue'
 import { Icon } from '@repo/ui'
 import { NodeResizer } from '@vue-flow/node-resizer'
 import type { OnResize } from '@vue-flow/node-resizer'
@@ -32,6 +32,8 @@ const childrenEdges = computed(() =>
 const emit = defineEmits<{
 	update: [id: string, attrs: Record<string, unknown>]
 	move: [position: XYPosition]
+	'click:node': [id: string, position: XYPosition]
+	'dblclick:node': [id: string, position: XYPosition]
 	'click:node:add': [
 		payload: { nodeId: string; handle: string; position: XYPosition; event?: MouseEvent }
 	]
@@ -44,6 +46,7 @@ const emit = defineEmits<{
 }>()
 
 const nodeData = computed(() => node.props.value.node?.data ?? node.props.value.data)
+
 const nodeType = computed(() => {
 	const type = nodeData.value?.nodeType
 	return type ? nodeMap.value[type] : undefined
@@ -109,15 +112,18 @@ function onAddEdge(connection: Connection) {
 			>
 				<Icon :icon="nodeType?.icon ?? 'lucide:infinity'" color="#ffffff" :size="16" />
 			</div>
-			<span class="text-14px font-medium text-#333">{{ nodeType?.displayName ?? '循环' }}</span>
+			<span class="text-14px font-medium text-#333">{{
+				node.props.value.node?.name ?? '节点标题'
+			}}</span>
 		</div>
 
 		<!-- 内部画布区域:虚线网格 + 占位内容 -->
 		<div class="loop-body flex-1 min-h-0 relative">
 			<div
-				class="absolute top-16px right-16px bottom-16px left-16px rounded-8px border-1 border-dashed border-#d9d9d9 bg-[repeating-linear-gradient(to_right,#e8e8e8_0,transparent_1px),repeating-linear-gradient(to_bottom,#e8e8e8_0,transparent_1px)] bg-[length:12px_12px]"
-			/>
-			<div class="absolute top-16px right-16px bottom-16px left-16px z-1">
+				class="absolute top-16px right-16px bottom-16px left-16px z-1 rounded-8px border-1 border-dashed border-#d9d9d9 nopan"
+				@click.stop
+				@dblclick.stop
+			>
 				<Canvas
 					:id="node.props.value.id"
 					:nodes="childrenNodes"
@@ -129,6 +135,10 @@ function onAddEdge(connection: Connection) {
 					:zoom-to-fit="false"
 					:max-zoom="1"
 					:min-zoom="1"
+					:pan-on-drag="false"
+					:auto-pan-on-node-drag="false"
+					@click:node="(id, position) => emit('click:node', id, position)"
+					@dblclick:node="(id, position) => emit('dblclick:node', id, position)"
 					@click:node:add="emit('click:node:add', $event)"
 					@create:node="onAddNode"
 					@create:connection:end="onAddEdge"

+ 4 - 0
packages/workflow/src/components/elements/nodes/render-types/NodeRenderer.vue

@@ -14,6 +14,8 @@ const node = useCanvasNodeContext()
 const nodeType = computed(() => node.props.value.data?.nodeType)
 
 defineEmits<{
+	'click:node': [id: string, position: XYPosition]
+	'dblclick:node': [id: string, position: XYPosition]
 	'click:node:add': [payload: { nodeId: string; handleId: string; event?: MouseEvent }]
 	'add-inner-node': []
 	'add-inner-edge': [connection: Connection]
@@ -26,6 +28,8 @@ defineEmits<{
 	<NodeLoop
 		v-else-if="nodeType === 'loop' || nodeType === 'iteration'"
 		v-bind="$attrs"
+		@click:node="(id, position) => $emit('click:node', id, position)"
+		@dblclick:node="(id, position) => $emit('dblclick:node', id, position)"
 		@click:node:add="$emit('click:node:add', $event)"
 		@add-inner-node="$emit('add-inner-node')"
 		@add-inner-edge="$emit('add-inner-edge', $event)"