diff --git a/apps/application/flow/step_node/condition_node/compare/contain_compare.py b/apps/application/flow/step_node/condition_node/compare/contain_compare.py
index fee2cddef..6073131a5 100644
--- a/apps/application/flow/step_node/condition_node/compare/contain_compare.py
+++ b/apps/application/flow/step_node/condition_node/compare/contain_compare.py
@@ -18,4 +18,6 @@ class ContainCompare(Compare):
return True
def compare(self, source_value, compare, target_value):
+ if isinstance(source_value, str):
+ return str(target_value) in source_value
return any([str(item) == str(target_value) for item in source_value])
diff --git a/apps/application/flow/step_node/direct_reply_node/i_reply_node.py b/apps/application/flow/step_node/direct_reply_node/i_reply_node.py
index 45bbebc38..268ee295c 100644
--- a/apps/application/flow/step_node/direct_reply_node/i_reply_node.py
+++ b/apps/application/flow/step_node/direct_reply_node/i_reply_node.py
@@ -39,7 +39,7 @@ class IReplyNode(INode):
return ReplyNodeParamsSerializer
def _run(self):
- return self.execute(**self.flow_params_serializer.data)
+ return self.execute(**self.node_params_serializer.data, **self.flow_params_serializer.data)
def execute(self, reply_type, stream, fields=None, content=None, **kwargs) -> NodeResult:
pass
diff --git a/apps/application/flow/step_node/direct_reply_node/impl/base_reply_node.py b/apps/application/flow/step_node/direct_reply_node/impl/base_reply_node.py
index 94a78a860..51dca9dc9 100644
--- a/apps/application/flow/step_node/direct_reply_node/impl/base_reply_node.py
+++ b/apps/application/flow/step_node/direct_reply_node/impl/base_reply_node.py
@@ -65,7 +65,7 @@ class BaseReplyNode(IReplyNode):
else:
result = self.generate_reply_content(content)
if stream:
- return NodeResult({'result': iter(AIMessageChunk(content=result))}, {},
+ return NodeResult({'result': iter([AIMessageChunk(content=result)])}, {},
_to_response=to_stream_response)
else:
return NodeResult({'result': AIMessage(content=result)}, {}, _to_response=to_response)
diff --git a/apps/application/flow/workflow_manage.py b/apps/application/flow/workflow_manage.py
index 12f4a5a06..ae3b6fde1 100644
--- a/apps/application/flow/workflow_manage.py
+++ b/apps/application/flow/workflow_manage.py
@@ -6,6 +6,8 @@
@date:2024/1/9 17:40
@desc:
"""
+import json
+import uuid
from typing import List, Dict
from langchain_core.prompts import PromptTemplate
@@ -172,3 +174,500 @@ class WorkflowManage:
def get_node_reference(self, reference_address: Dict):
node = self.get_node_by_id(reference_address.get('node_id'))
return node.context[reference_address.get('node_field')]
+
+
+json_str = """
+{
+ "nodes": [
+ {
+ "id": "base-node",
+ "type": "base-node",
+ "x": 200,
+ "y": 270,
+ "properties": {
+ "height": 200,
+ "stepName": "基本信息",
+ "node_data": {
+ "name": "",
+ "desc": "",
+ "prologue": "您好,我是 MaxKB 小助手,您可以向我提出 MaxKB 使用问题。"
+ }
+ }
+ },
+ {
+ "id": "start-node",
+ "type": "start-node",
+ "x": 140,
+ "y": 800,
+ "properties": {
+ "height": 200,
+ "stepName": "开始",
+ "output": [
+ {
+ "key": ""
+ }
+ ],
+ "fields": [
+ {
+ "label": "用户问题",
+ "value": "question"
+ }
+ ]
+ }
+ },
+ {
+ "id": "34902d3d-a3ff-497f-b8e1-0c34a44d7dd5",
+ "type": "search-dataset-node",
+ "x": 1490,
+ "y": 580,
+ "properties": {
+ "height": 200,
+ "stepName": "知识库检索",
+ "input": [
+ {
+ "key": "输入"
+ }
+ ],
+ "output": [
+ {
+ "key": "输出"
+ }
+ ],
+ "fields": [
+ {
+ "label": "检索结果",
+ "value": "data"
+ },
+ {
+ "label": "满足直接回答的分段内容",
+ "value": "paragraph"
+ }
+ ],
+ "node_data": {
+ "dataset_id_list": [
+ "e750b5f5-247a-11ef-8fc8-a8a1595801ab",
+ "1e42a226-1bfd-11ef-be5f-a8a1595801ab",
+ "e3b4ad8d-18f2-11ef-9a18-a8a1595801ab",
+ "861d1f5c-18f3-11ef-a40e-a8a1595801ab"
+ ],
+ "dataset_setting": {
+ "top_n": 3,
+ "similarity": 0.6,
+ "max_paragraph_char_number": 5000,
+ "search_mode": "embedding"
+ },
+ "question_reference_address": [
+ "start-node",
+ "question"
+ ]
+ }
+ }
+ },
+ {
+ "id": "34902d3d-a3ff-497f-b8e1-0c34a44d7dd6",
+ "type": "condition-node",
+ "x": 1080,
+ "y": 500,
+ "properties": {
+ "height": 200,
+ "width": 600,
+ "stepName": "判断器",
+ "input": [
+ {
+ "key": "输入"
+ }
+ ],
+ "output": [
+ {
+ "key": "9208"
+ },
+ {
+ "key": "1143"
+ },
+ {
+ "key": "输出"
+ }
+ ],
+ "node_data": {
+ "branch": [
+ {
+ "conditions": [
+ {
+ "field": [
+ "03597cb0-ed4c-4bcb-b25b-3b358f72b266",
+ "answer"
+ ],
+ "compare": "contain",
+ "value": "打招呼"
+ }
+ ],
+ "id": "2391",
+ "type": "IF",
+ "condition": "and"
+ },
+ {
+ "conditions": [
+ {
+ "field": [
+ "03597cb0-ed4c-4bcb-b25b-3b358f72b266",
+ "answer"
+ ],
+ "compare": "contain",
+ "value": "售前咨询"
+ }
+ ],
+ "id": "1143",
+ "type": "IF ELSE 1",
+ "condition": "and"
+ },
+ {
+ "conditions": [
+
+ ],
+ "id": "9208",
+ "type": "ELSE",
+ "condition": "and"
+ }
+ ]
+ }
+ }
+ },
+ {
+ "id": "03597cb0-ed4c-4bcb-b25b-3b358f72b266",
+ "type": "ai-chat-node",
+ "x": 580,
+ "y": 400,
+ "properties": {
+ "height": "",
+ "stepName": "AI 对话",
+ "input": [
+ {
+ "key": "输入"
+ }
+ ],
+ "output": [
+ {
+ "key": "输出"
+ }
+ ],
+ "node_data": {
+ "model_id": "9bdd1ab3-135b-11ef-b688-a8a1595801ab",
+ "system": "你是问题分析大师",
+ "prompt": "请直接返回所属的问题分类,不要说推理过程。用户问题为:{{context['start-node'].question}} 问题分类是:打招呼 售前咨询 售后咨询其他咨询",
+ "dialogue_number": 1
+ }
+ }
+ },
+ {
+ "id": "6649ee86-348c-4d68-9cad-71f0612beb05",
+ "type": "ai-chat-node",
+ "x": 2030,
+ "y": 500,
+ "properties": {
+ "height": "",
+ "stepName": "AI 对话",
+ "input": [
+ {
+ "key": "输入"
+ }
+ ],
+ "output": [
+ {
+ "key": "输出"
+ }
+ ],
+ "node_data": {
+ "model_id": "9bdd1ab3-135b-11ef-b688-a8a1595801ab",
+ "system": "你是售前咨询工程师",
+ "prompt": "已知信息:{{context['34902d3d-a3ff-497f-b8e1-0c34a44d7dd5'].data}}回答用户问题:{{context['start-node'].question}}",
+ "dialogue_number": 0
+ }
+ }
+ },
+ {
+ "id": "0004a9c9-e2fa-40ac-9215-2e1ad04f09c5",
+ "type": "ai-chat-node",
+ "x": 1360,
+ "y": 1300,
+ "properties": {
+ "height": "",
+ "stepName": "AI 对话",
+ "input": [
+ {
+ "key": "输入"
+ }
+ ],
+ "output": [
+ {
+ "key": "输出"
+ }
+ ],
+ "node_data": {
+ "model_id": "9bdd1ab3-135b-11ef-b688-a8a1595801ab",
+ "system": "你是售后咨询工程师",
+ "prompt": "{{context['start-node'].question}}",
+ "dialogue_number": 0
+ }
+ }
+ },
+ {
+ "id": "30c16d31-3881-48cd-991e-da3f99c45681",
+ "type": "reply-node",
+ "x": 1690,
+ "y": 170,
+ "properties": {
+ "height": "",
+ "stepName": "指定回复",
+ "input": [
+ {
+ "key": ""
+ }
+ ],
+ "output": [
+ {
+ "key": ""
+ }
+ ],
+ "node_data": {
+ "reply_type": "content",
+ "content": "你好,有什么需要帮助的吗",
+ "fields": [
+
+ ]
+ }
+ }
+ }
+ ],
+ "edges": [
+ {
+ "id": "214aa478-78ce-4c95-89aa-11f821bc65d2",
+ "type": "app-edge",
+ "sourceNodeId": "start-node",
+ "targetNodeId": "03597cb0-ed4c-4bcb-b25b-3b358f72b266",
+ "startPoint": {
+ "x": 300,
+ "y": 865.3335000000001
+ },
+ "endPoint": {
+ "x": 420,
+ "y": 677
+ },
+ "properties": {
+
+ },
+ "pointsList": [
+ {
+ "x": 300,
+ "y": 865.3335000000001
+ },
+ {
+ "x": 410,
+ "y": 865.3335000000001
+ },
+ {
+ "x": 310,
+ "y": 677
+ },
+ {
+ "x": 420,
+ "y": 677
+ }
+ ],
+ "sourceAnchorId": "start-node__right",
+ "targetAnchorId": "03597cb0-ed4c-4bcb-b25b-3b358f72b266_输入_left"
+ },
+ {
+ "id": "d56fb64a-4fc0-4779-911b-283a2238ef7b",
+ "type": "app-edge",
+ "sourceNodeId": "03597cb0-ed4c-4bcb-b25b-3b358f72b266",
+ "targetNodeId": "34902d3d-a3ff-497f-b8e1-0c34a44d7dd6",
+ "startPoint": {
+ "x": 740,
+ "y": 672
+ },
+ "endPoint": {
+ "x": 790,
+ "y": 678.6665
+ },
+ "properties": {
+
+ },
+ "pointsList": [
+ {
+ "x": 740,
+ "y": 672
+ },
+ {
+ "x": 850,
+ "y": 672
+ },
+ {
+ "x": 680,
+ "y": 678.6665
+ },
+ {
+ "x": 790,
+ "y": 678.6665
+ }
+ ],
+ "sourceAnchorId": "03597cb0-ed4c-4bcb-b25b-3b358f72b266_输出_right",
+ "targetAnchorId": "34902d3d-a3ff-497f-b8e1-0c34a44d7dd6_输入_left"
+ },
+ {
+ "id": "26fe01d6-8d41-4025-a637-e09f41c9b2c8",
+ "type": "app-edge",
+ "sourceNodeId": "34902d3d-a3ff-497f-b8e1-0c34a44d7dd6",
+ "targetNodeId": "30c16d31-3881-48cd-991e-da3f99c45681",
+ "startPoint": {
+ "x": 1370,
+ "y": 673.6665
+ },
+ "endPoint": {
+ "x": 1530,
+ "y": 286
+ },
+ "properties": {
+
+ },
+ "pointsList": [
+ {
+ "x": 1370,
+ "y": 673.6665
+ },
+ {
+ "x": 1480,
+ "y": 673.6665
+ },
+ {
+ "x": 1420,
+ "y": 286
+ },
+ {
+ "x": 1530,
+ "y": 286
+ }
+ ],
+ "sourceAnchorId": "34902d3d-a3ff-497f-b8e1-0c34a44d7dd6_9208_right",
+ "targetAnchorId": "30c16d31-3881-48cd-991e-da3f99c45681__left"
+ },
+ {
+ "id": "5c85d2bb-cb27-44ed-9e05-505f702381f6",
+ "type": "app-edge",
+ "sourceNodeId": "34902d3d-a3ff-497f-b8e1-0c34a44d7dd6",
+ "targetNodeId": "34902d3d-a3ff-497f-b8e1-0c34a44d7dd5",
+ "startPoint": {
+ "x": 1370,
+ "y": 697.6665
+ },
+ "endPoint": {
+ "x": 1330,
+ "y": 898.889
+ },
+ "properties": {
+
+ },
+ "pointsList": [
+ {
+ "x": 1370,
+ "y": 697.6665
+ },
+ {
+ "x": 1480,
+ "y": 697.6665
+ },
+ {
+ "x": 1220,
+ "y": 898.889
+ },
+ {
+ "x": 1330,
+ "y": 898.889
+ }
+ ],
+ "sourceAnchorId": "34902d3d-a3ff-497f-b8e1-0c34a44d7dd6_1143_right",
+ "targetAnchorId": "34902d3d-a3ff-497f-b8e1-0c34a44d7dd5_输入_left"
+ },
+ {
+ "id": "4d4b5740-910e-48b0-badd-8b9ce10e6e4e",
+ "type": "app-edge",
+ "sourceNodeId": "34902d3d-a3ff-497f-b8e1-0c34a44d7dd5",
+ "targetNodeId": "6649ee86-348c-4d68-9cad-71f0612beb05",
+ "startPoint": {
+ "x": 1650,
+ "y": 893.889
+ },
+ "endPoint": {
+ "x": 1870,
+ "y": 777
+ },
+ "properties": {
+
+ },
+ "pointsList": [
+ {
+ "x": 1650,
+ "y": 893.889
+ },
+ {
+ "x": 1760,
+ "y": 893.889
+ },
+ {
+ "x": 1760,
+ "y": 777
+ },
+ {
+ "x": 1870,
+ "y": 777
+ }
+ ],
+ "sourceAnchorId": "34902d3d-a3ff-497f-b8e1-0c34a44d7dd5_输出_right",
+ "targetAnchorId": "6649ee86-348c-4d68-9cad-71f0612beb05_输入_left"
+ },
+ {
+ "id": "9c446d4d-e500-4867-8d47-ed99f80b9b48",
+ "type": "app-edge",
+ "sourceNodeId": "34902d3d-a3ff-497f-b8e1-0c34a44d7dd6",
+ "targetNodeId": "0004a9c9-e2fa-40ac-9215-2e1ad04f09c5",
+ "startPoint": {
+ "x": 1370,
+ "y": 721.6665
+ },
+ "endPoint": {
+ "x": 1200,
+ "y": 1577
+ },
+ "properties": {
+
+ },
+ "pointsList": [
+ {
+ "x": 1370,
+ "y": 721.6665
+ },
+ {
+ "x": 1480,
+ "y": 721.6665
+ },
+ {
+ "x": 1090,
+ "y": 1577
+ },
+ {
+ "x": 1200,
+ "y": 1577
+ }
+ ],
+ "sourceAnchorId": "34902d3d-a3ff-497f-b8e1-0c34a44d7dd6_2391_right",
+ "targetAnchorId": "0004a9c9-e2fa-40ac-9215-2e1ad04f09c5_输入_left"
+ }
+ ]
+}
+"""
+f = Flow.new_instance(json.loads(json_str))
+_id = str(uuid.uuid1())
+w_manage = WorkflowManage(flow=f,
+ params={"history_chat_record": [], "question": "有企业版吗", "chat_id": _id,
+ "chat_record_id": _id,
+ "stream": True, "client_id": _id, "client_type": "xxxx"})
+w_manage.run()
diff --git a/apps/smartdoc/wsgi.py b/apps/smartdoc/wsgi.py
index e04ec5274..29adeb29f 100644
--- a/apps/smartdoc/wsgi.py
+++ b/apps/smartdoc/wsgi.py
@@ -25,3 +25,9 @@ def post_handler():
post_handler()
+
+
+def run():
+ from application.flow.workflow_manage import WorkflowManage
+
+
diff --git a/ui/src/workflow/common/NodeContainer.vue b/ui/src/workflow/common/NodeContainer.vue
index 371b228c1..7be819190 100644
--- a/ui/src/workflow/common/NodeContainer.vue
+++ b/ui/src/workflow/common/NodeContainer.vue
@@ -8,20 +8,6 @@
-
@@ -42,33 +28,7 @@ const height = ref<{
const resizeStepContainer = (wh: any) => {
if (wh.height) {
height.value.stepContainerHeight = wh.height
- props.nodeModel.setHeight(
- height.value.stepContainerHeight,
- height.value.inputContainerHeight,
- height.value.outputContainerHeight
- )
- }
-}
-
-const resetOutputContainer = (wh: { height: number; width: number }) => {
- if (wh.height) {
- height.value.outputContainerHeight = wh.height
- props.nodeModel.setHeight(
- height.value.stepContainerHeight,
- height.value.inputContainerHeight,
- height.value.outputContainerHeight
- )
- }
-}
-
-const resetInputContainer = (wh: { height: number; width: number }) => {
- if (wh.height) {
- height.value.inputContainerHeight = wh.height
- props.nodeModel.setHeight(
- height.value.stepContainerHeight,
- height.value.inputContainerHeight,
- height.value.outputContainerHeight
- )
+ props.nodeModel.setHeight(height.value.stepContainerHeight)
}
}
diff --git a/ui/src/workflow/common/app-node.ts b/ui/src/workflow/common/app-node.ts
index 7abf2b493..37ac06de9 100644
--- a/ui/src/workflow/common/app-node.ts
+++ b/ui/src/workflow/common/app-node.ts
@@ -47,24 +47,6 @@ class AppNode extends HtmlNode {
}
class AppNodeModel extends HtmlNodeModel {
- /**
- * 给model自定义添加字段方法
- */
- addField(item: any) {
- this.properties.output.unshift(item)
- this.setAttributes()
- // 为了保持节点顶部位置不变,在节点变化后,对节点进行一个位移,位移距离为添加高度的一半。
- this.move(0, 24 / 2)
- // 更新节点连接边的path
- this.incoming.edges.forEach((edge: any) => {
- // 调用自定义的更新方案
- edge.updatePathByAnchor()
- })
- this.outgoing.edges.forEach((edge: any) => {
- // 调用自定义的更新方案
- edge.updatePathByAnchor()
- })
- }
getOutlineStyle() {
const style = super.getOutlineStyle()
style.stroke = 'none'
@@ -87,12 +69,8 @@ class AppNodeModel extends HtmlNodeModel {
return style
}
- setHeight(height: number, inputContainerHeight: number, outputContainerHeight: number) {
- this.height = height + inputContainerHeight + outputContainerHeight + 100
- this.baseHeight = height
- this.inputContainerHeight = inputContainerHeight
- this.outputContainerHeight = outputContainerHeight
-
+ setHeight(height: number) {
+ this.height = height + 100
this.outgoing.edges.forEach((edge: any) => {
// 调用自定义的更新方案
edge.updatePathByAnchor()
@@ -104,7 +82,6 @@ class AppNodeModel extends HtmlNodeModel {
}
setAttributes() {
this.width = this.properties?.width || 340
-
const circleOnlyAsTarget = {
message: '只允许从右边的锚点连出',
validate: (sourceNode: any, targetNode: any, sourceAnchor: any) => {
@@ -120,50 +97,21 @@ class AppNodeModel extends HtmlNodeModel {
})
}
getDefaultAnchor() {
- const {
- id,
- x,
- y,
- width,
- height,
- properties: { input, output }
- } = this
-
- if (this.baseHeight === undefined) {
- this.baseHeight = 0
- }
- if (this.inputContainerHeight === undefined) {
- this.inputContainerHeight = 0
- }
- if (this.height === undefined) {
- this.height = 200
- }
- if (this.outputContainerHeight === undefined) {
- this.outputContainerHeight = 0
- }
-
+ const { id, x, y, width } = this
const anchors: any = []
- if (input) {
- input.forEach((field: any, index: any) => {
- anchors.push({
- x: x - width / 2 + 10,
- y: y - height / 2 + this.baseHeight + 35 + index * 24,
- id: `${id}_${field.key}_left`,
- edgeAddable: false,
- type: 'left'
- })
- })
- }
- if (output) {
- output.forEach((field: any, index: any) => {
- anchors.push({
- x: x + width / 2 - 10,
- y: y - height / 2 + this.baseHeight + this.inputContainerHeight + 30 + index * 24,
- id: `${id}_${field.key}_right`,
- type: 'right'
- })
- })
- }
+ anchors.push({
+ x: x - width / 2 + 10,
+ y: y,
+ id: `${id}`,
+ edgeAddable: false,
+ type: 'left'
+ })
+ anchors.push({
+ x: x + width / 2 - 10,
+ y: y,
+ id: `${id}`,
+ type: 'right'
+ })
return anchors
}
diff --git a/ui/src/workflow/common/edge.ts b/ui/src/workflow/common/edge.ts
index fb13bea36..dd38bc703 100644
--- a/ui/src/workflow/common/edge.ts
+++ b/ui/src/workflow/common/edge.ts
@@ -4,7 +4,10 @@ class CustomEdge2 extends BezierEdge {}
class CustomEdgeModel2 extends BezierEdgeModel {
getArrowStyle() {
- return { offset: 0 }
+ const arrowStyle = super.getArrowStyle()
+ arrowStyle.offset = 1
+ arrowStyle.verticalLength = 0
+ return arrowStyle
}
getEdgeStyle() {
@@ -13,6 +16,7 @@ class CustomEdgeModel2 extends BezierEdgeModel {
// svg属性
style.strokeWidth = 2
style.stroke = '#BBBFC4'
+ style.offset = 0
return style
}
/**
@@ -50,6 +54,7 @@ class CustomEdgeModel2 extends BezierEdgeModel {
x: targetAnchor.x,
y: targetAnchor.y
}
+
this.updateEndPoint(endPoint)
}
diff --git a/ui/src/workflow/index.vue b/ui/src/workflow/index.vue
index 600b4a5ea..dceabf452 100644
--- a/ui/src/workflow/index.vue
+++ b/ui/src/workflow/index.vue
@@ -61,34 +61,13 @@ const graphData = {
type: 'condition-node',
x: 810,
y: 760,
+
properties: {
height: 200,
width: 600,
stepName: '判断器',
input: [{ key: '输入' }],
- output: [{ key: '9208' }, { key: '1143' }, { key: '输出' }],
- node_data: {
- branch: [
- {
- conditions: [{ field: [], compare: '', value: '' }],
- id: '2391',
- type: 'IF',
- condition: 'and'
- },
- {
- conditions: [{ field: [], compare: '', value: '' }],
- id: '1143',
- type: 'IF ELSE 1',
- condition: 'and'
- },
- {
- conditions: [{ field: [], compare: '', value: '' }],
- id: '9208',
- type: 'ELSE',
- condition: 'and'
- }
- ]
- }
+ output: [{ key: '9208' }, { key: '1143' }, { key: '输出' }]
}
},
{
@@ -118,8 +97,6 @@ const graphData = {
properties: {
height: '',
stepName: 'AI 对话',
- input: [{ key: '输入' }],
- output: [{ key: '输出' }],
node_data: {
model_id: '',
system: '',
@@ -137,8 +114,6 @@ const graphData = {
properties: {
height: '',
stepName: 'AI 对话',
- input: [{ key: '输入' }],
- output: [{ key: '输出' }],
node_data: {
model_id: '',
system: '',
@@ -161,93 +136,7 @@ const graphData = {
}
}
],
- edges: [
- {
- id: '8dde4baf-0965-4999-9d37-f867ab16d638',
- type: 'app-edge',
- sourceNodeId: 'start-node',
- targetNodeId: '34902d3d-a3ff-497f-b8e1-0c34a44d7dd5',
- startPoint: { x: 340, y: 788 },
- endPoint: { x: 440, y: 469 },
- properties: {},
- pointsList: [
- { x: 340, y: 788 },
- { x: 450, y: 788 },
- { x: 330, y: 469 },
- { x: 440, y: 469 }
- ],
- sourceAnchorId: 'start-node_输出_right',
- targetAnchorId: '34902d3d-a3ff-497f-b8e1-0c34a44d7dd5_输入_left'
- },
- {
- id: 'b60de7b4-d8d2-4e7d-bba6-3738b9e523b9',
- type: 'app-edge',
- sourceNodeId: '34902d3d-a3ff-497f-b8e1-0c34a44d7dd5',
- targetNodeId: '34902d3d-a3ff-497f-b8e1-0c34a44d7dd6',
- startPoint: { x: 760, y: 503 },
- endPoint: { x: 520, y: 931.0625 },
- properties: {},
- pointsList: [
- { x: 760, y: 503 },
- { x: 870, y: 503 },
- { x: 410, y: 931.0625 },
- { x: 520, y: 931.0625 }
- ],
- sourceAnchorId: '34902d3d-a3ff-497f-b8e1-0c34a44d7dd5_输出_right',
- targetAnchorId: '34902d3d-a3ff-497f-b8e1-0c34a44d7dd6_输入_left'
- },
- {
- id: '8de0da85-b5d6-459a-8be9-4d00082baf1c',
- type: 'app-edge',
- sourceNodeId: '34902d3d-a3ff-497f-b8e1-0c34a44d7dd6',
- targetNodeId: '03597cb0-ed4c-4bcb-b25b-3b358f72b266',
- startPoint: { x: 1100, y: 926.0625 },
- endPoint: { x: 1170, y: 969 },
- properties: {},
- pointsList: [
- { x: 1100, y: 926.0625 },
- { x: 1210, y: 926.0625 },
- { x: 1060, y: 969 },
- { x: 1170, y: 969 }
- ],
- sourceAnchorId: '34902d3d-a3ff-497f-b8e1-0c34a44d7dd6_9208_right',
- targetAnchorId: '03597cb0-ed4c-4bcb-b25b-3b358f72b266_输入_left'
- },
- {
- id: '3e66821a-ce0a-4ef9-a6cf-ea4095158261',
- type: 'app-edge',
- sourceNodeId: '34902d3d-a3ff-497f-b8e1-0c34a44d7dd6',
- targetNodeId: '6649ee86-348c-4d68-9cad-71f0612beb05',
- startPoint: { x: 1100, y: 950.0625 },
- endPoint: { x: 1160, y: 1269 },
- properties: {},
- pointsList: [
- { x: 1100, y: 950.0625 },
- { x: 1210, y: 950.0625 },
- { x: 1050, y: 1269 },
- { x: 1160, y: 1269 }
- ],
- sourceAnchorId: '34902d3d-a3ff-497f-b8e1-0c34a44d7dd6_1143_right',
- targetAnchorId: '6649ee86-348c-4d68-9cad-71f0612beb05_输入_left'
- },
- {
- id: 'cc52ab90-58e7-4f54-9660-d9fb16f776ea',
- type: 'app-edge',
- sourceNodeId: '34902d3d-a3ff-497f-b8e1-0c34a44d7dd6',
- targetNodeId: '0004a9c9-e2fa-40ac-9215-2e1ad04f09c5',
- startPoint: { x: 1100, y: 1016.75 },
- endPoint: { x: 1200, y: 1413 },
- properties: {},
- pointsList: [
- { x: 1100, y: 974.0625 },
- { x: 1210, y: 974.0625 },
- { x: 1090, y: 1579 },
- { x: 1200, y: 1579 }
- ],
- sourceAnchorId: '34902d3d-a3ff-497f-b8e1-0c34a44d7dd6_输出_right',
- targetAnchorId: '0004a9c9-e2fa-40ac-9215-2e1ad04f09c5_输入_left'
- }
- ]
+ edges: []
}
const lf = ref()
@@ -318,6 +207,11 @@ onMounted(() => {
lf.value.setDefaultEdgeType('app-edge')
lf.value.render(graphData)
+ lf.value.graphModel.eventCenter.on('delete_edge', (id_list: Array) => {
+ id_list.forEach((id: string) => {
+ lf.value.deleteEdge(id)
+ })
+ })
}
})
const validate = () => {
diff --git a/ui/src/workflow/nodes/condition-node/index.ts b/ui/src/workflow/nodes/condition-node/index.ts
index 117af80f6..b3cf5fea6 100644
--- a/ui/src/workflow/nodes/condition-node/index.ts
+++ b/ui/src/workflow/nodes/condition-node/index.ts
@@ -1,12 +1,69 @@
import ConditioNodeVue from './index.vue'
+import { cloneDeep, set } from 'lodash'
import { AppNode, AppNodeModel } from '@/workflow/common/app-node'
class ConditioNode extends AppNode {
constructor(props: any) {
super(props, ConditioNodeVue)
}
}
+const get_up_index_height = (condition_list: Array, index: number) => {
+ return condition_list
+ .filter((item, i) => i < index)
+ .map((item) => item.height + 8)
+ .reduce((x, y) => x + y, 0)
+}
+class ConditionModel extends AppNodeModel {
+ refreshBranch() {
+ // 为了保持节点顶部位置不变,在节点变化后,对节点进行一个位移,位移距离为添加高度的一半。
+ this.move(0, 24 / 2)
+ // 更新节点连接边的path
+ this.incoming.edges.forEach((edge: any) => {
+ // 调用自定义的更新方案
+ edge.updatePathByAnchor()
+ })
+ this.outgoing.edges.forEach((edge: any) => {
+ edge.updatePathByAnchor()
+ })
+ }
+ getDefaultAnchor() {
+ const {
+ id,
+ x,
+ y,
+ width,
+ height,
+ properties: { barnch_condition_list }
+ } = this
+ if (this.height === undefined) {
+ this.height = 200
+ }
+ const anchors: any = []
+ anchors.push({
+ x: x - width / 2 + 10,
+ y: y,
+ id: `${id}`,
+ edgeAddable: false,
+ type: 'left'
+ })
+
+ if (barnch_condition_list) {
+ for (let index = 0; index < barnch_condition_list.length; index++) {
+ const element = barnch_condition_list[index]
+ const h = get_up_index_height(barnch_condition_list, index)
+ anchors.push({
+ x: x + width / 2 - 10,
+ y: y - height / 2 + 75 + h + element.height / 2,
+ id: `${id}_${element.id}_right`,
+ type: 'right'
+ })
+ }
+ }
+
+ return anchors
+ }
+}
export default {
type: 'condition-node',
- model: AppNodeModel,
+ model: ConditionModel,
view: ConditioNode
}
diff --git a/ui/src/workflow/nodes/condition-node/index.vue b/ui/src/workflow/nodes/condition-node/index.vue
index d56ef73a0..f6f195460 100644
--- a/ui/src/workflow/nodes/condition-node/index.vue
+++ b/ui/src/workflow/nodes/condition-node/index.vue
@@ -12,8 +12,13 @@
@mousedown.stop
@mousemove.stop
>
-
-
+
+
{{ item.type }}
@@ -110,9 +115,10 @@ import { cloneDeep, set } from 'lodash'
import NodeContainer from '@/workflow/common/NodeContainer.vue'
import NodeCascader from '@/workflow/common/NodeCascader.vue'
import type { FormInstance } from 'element-plus'
-import { ref, computed, onMounted } from 'vue'
+import { ref, computed, onMounted, nextTick } from 'vue'
import { randomId } from '@/utils/utils'
import { compareList } from '@/workflow/common/data'
+
const props = defineProps<{ nodeModel: any }>()
const form = {
branch: [
@@ -137,12 +143,28 @@ const form = {
]
}
+const resizeCondition = (wh: any, row: any, index: number) => {
+ const barnch_condition_list = cloneDeep(
+ props.nodeModel.properties.barnch_condition_list
+ ? props.nodeModel.properties.barnch_condition_list
+ : []
+ )
+ const new_barnch_condition_list = barnch_condition_list.map((item: any) => {
+ if (item.id === row.id) {
+ return { ...item, height: wh.height, index: index }
+ }
+ return item
+ })
+ set(props.nodeModel.properties, 'barnch_condition_list', new_barnch_condition_list)
+ refreshBranchAnchor(props.nodeModel.properties.node_data.branch, true)
+}
const form_data = computed({
get: () => {
if (props.nodeModel.properties.node_data) {
return props.nodeModel.properties.node_data
} else {
set(props.nodeModel.properties, 'node_data', form)
+ refreshBranchAnchor(form.branch, true)
}
return props.nodeModel.properties.node_data
},
@@ -157,16 +179,6 @@ const validate = () => {
ConditionNodeFormRef.value?.validate()
}
-// const judgeLabel = (index: number) => {
-// if (index === 0) {
-// return 'IF'
-// } else if (index === form_data.value.branch.length - 1) {
-// return 'ELSE'
-// } else {
-// return 'ELSE IF ' + index
-// }
-// }
-
function addBranch() {
const list = cloneDeep(props.nodeModel.properties.node_data.branch)
const obj = {
@@ -182,9 +194,31 @@ function addBranch() {
condition: 'and'
}
list.splice(list.length - 1, 0, obj)
- props.nodeModel.addField({ key: obj.id })
+ refreshBranchAnchor(list, true)
set(props.nodeModel.properties.node_data, 'branch', list)
}
+function refreshBranchAnchor(list: Array
, is_add: boolean) {
+ const barnch_condition_list = cloneDeep(
+ props.nodeModel.properties.barnch_condition_list
+ ? props.nodeModel.properties.barnch_condition_list
+ : []
+ )
+ const new_barnch_condition_list = list
+ .map((item, index) => {
+ const find = barnch_condition_list.find((b) => b.id === item.id)
+ if (find) {
+ return { index: index, height: find.height, id: item.id }
+ } else {
+ if (is_add) {
+ return { index: index, height: 12, id: item.id }
+ }
+ }
+ })
+ .filter((item) => item)
+
+ set(props.nodeModel.properties, 'barnch_condition_list', new_barnch_condition_list)
+ props.nodeModel.refreshBranch()
+}
function addCondition(index: number) {
const list = cloneDeep(props.nodeModel.properties.node_data.branch)
@@ -200,7 +234,18 @@ function deleteCondition(index: number, cIndex: number) {
const list = cloneDeep(props.nodeModel.properties.node_data.branch)
list[index]['conditions'].splice(cIndex, 1)
if (list[index]['conditions'].length === 0) {
- list.splice(index, 1)
+ const delete_edge = list.splice(index, 1)
+ const delete_target_anchor_id_list = delete_edge.map(
+ (item) => props.nodeModel.id + '_' + item.id + '_right'
+ )
+
+ props.nodeModel.graphModel.eventCenter.emit(
+ 'delete_edge',
+ props.nodeModel.outgoing.edges
+ .filter((item) => delete_target_anchor_id_list.includes(item.sourceAnchorId))
+ .map((item) => item.id)
+ )
+ refreshBranchAnchor(list, false)
}
set(props.nodeModel.properties.node_data, 'branch', list)
}