From 91e6f493429ed471b23799fad65beba6f70881da Mon Sep 17 00:00:00 2001 From: lanyuanxiaoyao Date: Tue, 15 Jul 2025 23:19:33 +0800 Subject: [PATCH] =?UTF-8?q?feat(web):=20=E5=A2=9E=E5=8A=A0=E5=88=A4?= =?UTF-8?q?=E6=96=AD=E8=8A=82=E7=82=B9=E5=AF=B9=E4=B8=8D=E5=90=8C=E7=B1=BB?= =?UTF-8?q?=E5=9E=8B=E7=9A=84=E9=80=82=E9=85=8D=E5=92=8C=E5=A4=84=E7=90=86?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../client/src/components/flow/Helper.tsx | 46 ++++++++++++++++++- .../src/components/flow/node/CodeNode.tsx | 17 +------ .../src/components/flow/node/LlmNode.tsx | 2 +- .../src/components/flow/node/SwitchNode.tsx | 32 ++++++++----- .../src/components/flow/node/TemplateNode.tsx | 2 +- service-web/client/src/pages/Test.tsx | 2 +- 6 files changed, 71 insertions(+), 30 deletions(-) diff --git a/service-web/client/src/components/flow/Helper.tsx b/service-web/client/src/components/flow/Helper.tsx index 3413f31..a28da32 100644 --- a/service-web/client/src/components/flow/Helper.tsx +++ b/service-web/client/src/components/flow/Helper.tsx @@ -100,6 +100,24 @@ export const generateAllIncomerOutputVariablesFormOptions: (id: string, inputSch })) } +type ConditionOperator = string | { label: string, value: string } +const textOperators: ConditionOperator[] = ['equal', 'not_equal', 'is_empty', 'is_not_empty', 'like', 'not_like', 'starts_with', 'ends_with'] +const textDefaultOperator: string = 'equal' +const booleanOperators: ConditionOperator[] = [ + {label: '为真', value: 'is_true'}, + {label: '为假', value: 'is_false'}, +] +const booleanDefaultOperator: string = 'is_true' +const numberOperators: ConditionOperator[] = [ + 'equal', + 'not_equal', + {label: '大于', value: 'greater'}, + {label: '大于或等于', value: 'greater_equal'}, + {label: '小于', value: 'less'}, + {label: '小于或等于', value: 'less_equal'}, +] +const numberDefaultOperator: string = 'equal' + export const generateAllIncomerOutputVariablesConditions: (id: string, inputSchema: Record>, nodes: Node[], edges: Edge[], data: any) => Option[] = (id, inputSchema, nodes, edges, data) => { let optionMap: Record = {} for (const item of getAllIncomerNodeOutputVariables(id, inputSchema, nodes, edges, data)) { @@ -108,8 +126,34 @@ export const generateAllIncomerOutputVariablesConditions: (id: string, inputSche } optionMap[item.group].push({ label: item.name, - type: item.type, + type: 'custom', name: item.variable, + ...(item.type === 'text' ? { + value: { + type: 'input-text', + required: true, + clearable: true, + }, + defaultOp: textDefaultOperator, + operators: textOperators, + } : {}), + ...(item.type === 'boolean' ? { + value: { + type: 'wrapper', + size: 'none', + }, + defaultOp: booleanDefaultOperator, + operators: booleanOperators, + } : {}), + ...(item.type === 'number' ? { + value: { + type: 'input-number', + required: true, + clearable: true, + }, + defaultOp: numberDefaultOperator, + operators: numberOperators, + } : {}), }) } return Object.keys(optionMap) diff --git a/service-web/client/src/components/flow/node/CodeNode.tsx b/service-web/client/src/components/flow/node/CodeNode.tsx index 6619b41..fc9a6ed 100644 --- a/service-web/client/src/components/flow/node/CodeNode.tsx +++ b/service-web/client/src/components/flow/node/CodeNode.tsx @@ -1,6 +1,6 @@ import type {NodeProps} from '@xyflow/react' import {Tag} from 'antd' -import React, {useCallback, useEffect} from 'react' +import React, {useCallback} from 'react' import {useContextStore} from '../store/ContextStore.ts' import {useDataStore} from '../store/DataStore.ts' import {useFlowStore} from '../store/FlowStore.ts' @@ -14,24 +14,11 @@ const languageMap: Record = { const CodeNode = (props: NodeProps) => { const {getNodes, getEdges} = useFlowStore() - const {getData, mergeDataById, getDataById} = useDataStore() + const {getData, getDataById} = useDataStore() const {getInputSchema} = useContextStore() const nodeData = getDataById(props.id) - useEffect(() => { - mergeDataById( - props.id, - { - outputs: { - result: { - type: 'string', - }, - }, - }, - ) - }, [props.id]) - const columnsSchema = useCallback(() => [ ...inputsFormColumns(props.id, getInputSchema(), getNodes(), getEdges(), getData()), { diff --git a/service-web/client/src/components/flow/node/LlmNode.tsx b/service-web/client/src/components/flow/node/LlmNode.tsx index 2c46375..de4adb8 100644 --- a/service-web/client/src/components/flow/node/LlmNode.tsx +++ b/service-web/client/src/components/flow/node/LlmNode.tsx @@ -24,7 +24,7 @@ const LlmNode = (props: NodeProps) => { { outputs: { text: { - type: 'string', + type: 'text', }, }, }, diff --git a/service-web/client/src/components/flow/node/SwitchNode.tsx b/service-web/client/src/components/flow/node/SwitchNode.tsx index 92977ab..d105f2d 100644 --- a/service-web/client/src/components/flow/node/SwitchNode.tsx +++ b/service-web/client/src/components/flow/node/SwitchNode.tsx @@ -26,17 +26,27 @@ const SwitchNode = (props: NodeProps) => { const columnsSchema = useCallback(() => [ { - type: 'condition-builder', - name: 'condition', - label: '判断条件', - fields: generateAllIncomerOutputVariablesConditions( - props.id, - getInputSchema(), - getNodes(), - getEdges(), - getData(), - ), - }, + type: 'combo', + name: 'conditions', + label: '分支', + multiple: true, + required: true, + items: [ + { + type: 'condition-builder', + name: 'condition', + label: '条件', + required: true, + fields: generateAllIncomerOutputVariablesConditions( + props.id, + getInputSchema(), + getNodes(), + getEdges(), + getData(), + ), + }, + ] + } ], [props.id]) return ( diff --git a/service-web/client/src/components/flow/node/TemplateNode.tsx b/service-web/client/src/components/flow/node/TemplateNode.tsx index 98941e5..14ad09a 100644 --- a/service-web/client/src/components/flow/node/TemplateNode.tsx +++ b/service-web/client/src/components/flow/node/TemplateNode.tsx @@ -26,7 +26,7 @@ const TemplateNode = (props: NodeProps) => { { outputs: { text: { - type: 'string', + type: 'text', }, }, }, diff --git a/service-web/client/src/pages/Test.tsx b/service-web/client/src/pages/Test.tsx index d93cf7a..62172ab 100644 --- a/service-web/client/src/pages/Test.tsx +++ b/service-web/client/src/pages/Test.tsx @@ -4,7 +4,7 @@ import type {GraphData} from '../components/flow/types.ts' function Test() { // language=JSON - const [graphData] = useState(JSON.parse('{\n "nodes": [\n {\n "id": "QxNrkChBWQ",\n "type": "loop-node",\n "position": {\n "x": 742,\n "y": 119\n },\n "data": {},\n "measured": {\n "width": 458,\n "height": 368\n },\n "selected": true,\n "dragging": false,\n "width": 458,\n "height": 368,\n "resizing": false\n },\n {\n "id": "MzEitlOusl",\n "type": "llm-node",\n "position": {\n "x": 47,\n "y": 135\n },\n "data": {},\n "measured": {\n "width": 256,\n "height": 110\n },\n "selected": false,\n "dragging": false,\n "extent": "parent",\n "parentId": "QxNrkChBWQ"\n },\n {\n "id": "bivXSpiLaI",\n "type": "code-node",\n "position": {\n "x": 381,\n "y": 181\n },\n "data": {},\n "measured": {\n "width": 256,\n "height": 110\n },\n "selected": false,\n "dragging": false\n }\n ],\n "edges": [],\n "data": {\n "MzEitlOusl": {\n "node": {\n "name": "大模型",\n "description": "使用大模型对话"\n },\n "outputs": {\n "text": {\n "type": "string"\n }\n },\n "model": "qwen3",\n "systemPrompt": "你是个好人",\n "finished": true\n },\n "bivXSpiLaI": {\n "node": {\n "name": "代码执行",\n "description": "执行自定义的处理代码"\n },\n "outputs": {\n "result": {\n "type": "text"\n }\n },\n "type": "javascript",\n "content": "console.log(\'hello\')",\n "inputs": {\n "text": {\n "variable": "MzEitlOusl.text"\n }\n },\n "finished": true\n },\n "QxNrkChBWQ": {\n "node": {\n "name": "循环",\n "description": "实现循环执行流程"\n },\n "finished": true\n }\n }\n}')) + const [graphData] = useState(JSON.parse('{\n "nodes": [\n {\n "id": "QxNrkChBWQ",\n "type": "loop-node",\n "position": {\n "x": 742,\n "y": 119\n },\n "data": {},\n "measured": {\n "width": 458,\n "height": 368\n },\n "selected": false,\n "dragging": false,\n "width": 458,\n "height": 368,\n "resizing": false\n },\n {\n "id": "MzEitlOusl",\n "type": "llm-node",\n "position": {\n "x": 47,\n "y": 135\n },\n "data": {},\n "measured": {\n "width": 256,\n "height": 108\n },\n "selected": false,\n "dragging": false,\n "extent": "parent",\n "parentId": "QxNrkChBWQ"\n },\n {\n "id": "bivXSpiLaI",\n "type": "code-node",\n "position": {\n "x": 100,\n "y": 188\n },\n "data": {},\n "measured": {\n "width": 256,\n "height": 108\n },\n "selected": false,\n "dragging": false\n },\n {\n "id": "JsUwvjkJCW",\n "type": "switch-node",\n "position": {\n "x": 400,\n "y": 267\n },\n "data": {},\n "measured": {\n "width": 256,\n "height": 159\n },\n "selected": true,\n "dragging": false\n }\n ],\n "edges": [\n {\n "source": "bivXSpiLaI",\n "sourceHandle": "source",\n "target": "JsUwvjkJCW",\n "id": "xy-edge__bivXSpiLaIsource-JsUwvjkJCW"\n }\n ],\n "data": {\n "MzEitlOusl": {\n "node": {\n "name": "大模型",\n "description": "使用大模型对话"\n },\n "outputs": {\n "text": {\n "type": "text"\n }\n },\n "model": "qwen3",\n "systemPrompt": "你是个好人",\n "finished": true\n },\n "bivXSpiLaI": {\n "node": {\n "name": "代码执行",\n "description": "执行自定义的处理代码"\n },\n "outputs": {\n "text": {\n "type": "text"\n },\n "condition": {\n "type": "boolean"\n },\n "count": {\n "type": "number"\n },\n "person": {\n "type": "object"\n },\n "words": {\n "type": "array-text"\n },\n "people": {\n "type": "array-object"\n }\n },\n "type": "javascript",\n "content": "console.log(\'hello\')",\n "inputs": {\n "text": {\n "variable": "MzEitlOusl.text"\n }\n },\n "finished": true\n },\n "QxNrkChBWQ": {\n "node": {\n "name": "循环",\n "description": "实现循环执行流程"\n },\n "finished": true\n },\n "JsUwvjkJCW": {\n "node": {\n "name": "分支",\n "description": "根据不同的情况前往不同的分支"\n }\n }\n }\n}')) return (