|
|
@@ -66,6 +66,7 @@
|
|
|
@delete:connection="handleDeleteEdge"
|
|
|
@dragover="onDragOver"
|
|
|
@dragleave="onDragLeave"
|
|
|
+ @create:connection:cancelled="onConnectionOpenNodeLibary"
|
|
|
class="bg-#f5f5f5"
|
|
|
>
|
|
|
<Toolbar
|
|
|
@@ -99,6 +100,7 @@ import { agent } from '@repo/api-service'
|
|
|
|
|
|
import RunWorkflow from '@/components/RunWorkflow/index.vue'
|
|
|
import EditorFooter from '@/features/editorFooter/index.vue'
|
|
|
+import NodeLibary from '@/features/nodeLibary/index.vue'
|
|
|
import Toolbar from '@/features/toolbar/index.vue'
|
|
|
import Setter from '@/features/setter/index.vue'
|
|
|
|
|
|
@@ -108,7 +110,7 @@ import { Workflow, useDragAndDrop } from '@repo/workflow'
|
|
|
|
|
|
import { dayjs, ElMessage, ElMessageBox } from 'element-plus'
|
|
|
|
|
|
-import type { IWorkflow, XYPosition, Connection } from '@repo/workflow'
|
|
|
+import type { IWorkflow, XYPosition, Connection, ConnectStartEvent } from '@repo/workflow'
|
|
|
import { useRunnerStore } from '@/store/modules/runner.store'
|
|
|
|
|
|
const layout = inject<{ setMainStyle: (style: CSSProperties) => void }>('layout')
|
|
|
@@ -209,7 +211,7 @@ const toWorkflowNode = (node: any) => {
|
|
|
width,
|
|
|
height,
|
|
|
zIndex: node?.zIndex ?? schema?.zIndex ?? 1,
|
|
|
- selected: !!node?.selected,
|
|
|
+ selected: false,
|
|
|
data: {
|
|
|
...(schema?.data || {}),
|
|
|
...(node?.data || {}),
|
|
|
@@ -222,48 +224,50 @@ const toWorkflowNode = (node: any) => {
|
|
|
}
|
|
|
}
|
|
|
|
|
|
-const resolveOverlapPositions = (nodes: any[]) => {
|
|
|
- const positionCountMap = new Map<string, number>()
|
|
|
- const gapX = 220
|
|
|
- const gapY = 140
|
|
|
-
|
|
|
- return nodes.map((node) => {
|
|
|
- const x = Number(node?.position?.x ?? 20)
|
|
|
- const y = Number(node?.position?.y ?? 30)
|
|
|
- const key = `${x},${y}`
|
|
|
- const currentCount = positionCountMap.get(key) ?? 0
|
|
|
- positionCountMap.set(key, currentCount + 1)
|
|
|
+const normalizeEdgeEndpoints = (
|
|
|
+ edge: { source: string; target: string },
|
|
|
+ nodes: Array<{ id: string; parentId?: string }>
|
|
|
+) => {
|
|
|
+ const sourceNode = nodes.find((node) => node.id === edge.source)
|
|
|
+ const targetNode = nodes.find((node) => node.id === edge.target)
|
|
|
|
|
|
- if (currentCount === 0) {
|
|
|
- return node
|
|
|
- }
|
|
|
+ const sourceParentId = sourceNode?.parentId || ''
|
|
|
+ const targetParentId = targetNode?.parentId || ''
|
|
|
|
|
|
- const row = Math.floor(currentCount / 4)
|
|
|
- const col = currentCount % 4
|
|
|
- const nextPosition = {
|
|
|
- x: x + col * gapX,
|
|
|
- y: y + row * gapY
|
|
|
+ if (sourceParentId && sourceParentId !== targetParentId) {
|
|
|
+ return {
|
|
|
+ source: sourceParentId,
|
|
|
+ target: edge.target
|
|
|
}
|
|
|
+ }
|
|
|
|
|
|
+ if (targetParentId && targetParentId !== sourceParentId) {
|
|
|
return {
|
|
|
- ...node,
|
|
|
- position: nextPosition,
|
|
|
- data: {
|
|
|
- ...(node?.data || {}),
|
|
|
- position: nextPosition
|
|
|
- }
|
|
|
+ source: edge.source,
|
|
|
+ target: targetParentId
|
|
|
}
|
|
|
- })
|
|
|
+ }
|
|
|
+
|
|
|
+ return edge
|
|
|
}
|
|
|
|
|
|
-const toWorkflowEdge = (edge: any, index: number) => {
|
|
|
+const toWorkflowEdge = (
|
|
|
+ edge: any,
|
|
|
+ index: number,
|
|
|
+ nodes: Array<{ id: string; parentId?: string }> = []
|
|
|
+) => {
|
|
|
if (!edge || typeof edge !== 'object' || !edge.source || !edge.target) {
|
|
|
return null
|
|
|
}
|
|
|
|
|
|
+ const normalizedEdge = normalizeEdgeEndpoints(edge, nodes)
|
|
|
+
|
|
|
return {
|
|
|
...edge,
|
|
|
- id: edge.id || `edge-${edge.source}-${edge.target}-${index}`,
|
|
|
+ ...normalizedEdge,
|
|
|
+ sourceHandle: edge.sourceHandle === 'source' ? `${edge.source}-source` : edge.sourceHandle,
|
|
|
+ targetHandle: edge.targetHandle === 'target' ? `${edge.target}-target` : edge.targetHandle,
|
|
|
+ id: edge.id || `edge-${normalizedEdge.source}-${normalizedEdge.target}-${index}`,
|
|
|
type: 'canvas-edge',
|
|
|
data: edge.data || {}
|
|
|
}
|
|
|
@@ -284,20 +288,14 @@ const loadAgentWorkflow = async (agentId: string) => {
|
|
|
throw new Error('获取智能体信息失败')
|
|
|
}
|
|
|
|
|
|
- const mappedNodes = (result.nodes || []).map(toWorkflowNode)
|
|
|
- const positionedNodes = resolveOverlapPositions(mappedNodes)
|
|
|
+ const normalizedNodes = (result.nodes || []).map(toWorkflowNode)
|
|
|
|
|
|
workflow.value = {
|
|
|
- id: result.id || agentId,
|
|
|
- name: result.name || 'workflow_1',
|
|
|
- created: dayjs().format('MM 月 DD 日'),
|
|
|
- nodes: positionedNodes,
|
|
|
- edges: (result.edges || []).map(toWorkflowEdge).filter(Boolean),
|
|
|
- tags: workflow.value?.tags || [],
|
|
|
- conversation_variables: result.conversation_variables || [],
|
|
|
- env_variables: result.env_variables || [],
|
|
|
- profilePhoto: result.profilePhoto,
|
|
|
- viewPort: result.viewPort
|
|
|
+ ...(result as unknown as IWorkflow),
|
|
|
+ nodes: normalizedNodes,
|
|
|
+ edges: (result.edges || []).map((edge: any, index: number) =>
|
|
|
+ toWorkflowEdge(edge, index, normalizedNodes)
|
|
|
+ )
|
|
|
}
|
|
|
await nextTick()
|
|
|
} catch (error) {
|
|
|
@@ -436,7 +434,8 @@ const handleRunSelectedNode = async () => {
|
|
|
const response = await agent.postAgentDoExecute({
|
|
|
appAgentId: workflow.value.id,
|
|
|
start_node_id: nodeID.value,
|
|
|
- is_debugger: true
|
|
|
+ is_debugger: true,
|
|
|
+ params: {}
|
|
|
})
|
|
|
const agentRunnerKey = response?.result
|
|
|
if (agentRunnerKey) {
|
|
|
@@ -460,7 +459,8 @@ const handleRunNode = async (id: string) => {
|
|
|
const response = await agent.postAgentDoExecute({
|
|
|
appAgentId: workflow.value.id,
|
|
|
start_node_id: id,
|
|
|
- is_debugger: true
|
|
|
+ is_debugger: true,
|
|
|
+ params: {}
|
|
|
})
|
|
|
const agentRunnerKey = response?.result
|
|
|
if (agentRunnerKey) {
|
|
|
@@ -548,7 +548,6 @@ const handleNodeCreate = (value: { type: string; position?: XYPosition } | strin
|
|
|
ElMessage.error('新增节点失败')
|
|
|
})
|
|
|
}
|
|
|
- console.log(workflow.value?.nodes, 'workflow.nodes')
|
|
|
}
|
|
|
const handleNodeClick = (id: string, _position: XYPosition) => {
|
|
|
nodeID.value = id
|
|
|
@@ -589,8 +588,13 @@ const handleDelete = () => {
|
|
|
/**
|
|
|
* 创建连线
|
|
|
*/
|
|
|
+const normalizeConnectionEndpoints = (connection: Connection) => {
|
|
|
+ return normalizeEdgeEndpoints(connection, workflow.value?.nodes || [])
|
|
|
+}
|
|
|
+
|
|
|
const onCreateConnection = async (connection: Connection) => {
|
|
|
- const { source, target, sourceHandle } = connection
|
|
|
+ const { sourceHandle } = connection
|
|
|
+ const { source, target } = normalizeConnectionEndpoints(connection)
|
|
|
|
|
|
const params: {
|
|
|
appAgentId: string
|
|
|
@@ -605,7 +609,8 @@ const onCreateConnection = async (connection: Connection) => {
|
|
|
zIndex: 1
|
|
|
}
|
|
|
|
|
|
- if (sourceHandle && sourceHandle !== 'source' && sourceHandle !== 'target') {
|
|
|
+ // 需要传sourceHandle的情况是中间带"_"
|
|
|
+ if (sourceHandle && sourceHandle.includes('_')) {
|
|
|
params.sourceHandle = sourceHandle
|
|
|
}
|
|
|
|
|
|
@@ -707,6 +712,14 @@ const handleUpdateNodeProps = (id: string, attrs: Record<string, unknown>) => {
|
|
|
} else {
|
|
|
Object.assign(node, attrs)
|
|
|
}
|
|
|
+ agent
|
|
|
+ .postAgentDoUpdateAgentNode(buildUpdateNodePayload(node))
|
|
|
+ .then((response) => {
|
|
|
+ handleApiResult(response, undefined, '更新节点失败')
|
|
|
+ })
|
|
|
+ .catch((error) => {
|
|
|
+ console.error('postDoUpdateAgentNode error', error)
|
|
|
+ })
|
|
|
}
|
|
|
}
|
|
|
|
|
|
@@ -754,6 +767,17 @@ const handleChangeEnvVars = async (
|
|
|
await loadAgentWorkflow(workflow.value.id)
|
|
|
}
|
|
|
|
|
|
+/**
|
|
|
+ * 连线取消时
|
|
|
+ */
|
|
|
+const onConnectionOpenNodeLibary = (event: {
|
|
|
+ handle: ConnectStartEvent
|
|
|
+ position: XYPosition
|
|
|
+ e: MouseEvent
|
|
|
+}) => {
|
|
|
+ // TODO: 在这个对应位置(可以需要转化成实际坐标)打开节点弹窗,选中节点在对应位置添加节点
|
|
|
+}
|
|
|
+
|
|
|
onBeforeUnmount(() => {
|
|
|
if (saveAgentTimer.value) window.clearTimeout(saveAgentTimer.value)
|
|
|
if (saveVarsTimer.value) window.clearTimeout(saveVarsTimer.value)
|