1016 lines
24 KiB
TypeScript
1016 lines
24 KiB
TypeScript
/*
|
|
* @Author: ZhaoYing
|
|
* @Date: 2026-02-03 15:06:18
|
|
* @Last Modified by: ZhaoYing
|
|
* @Last Modified time: 2026-04-03 20:28:08
|
|
*/
|
|
import LoopNode from './components/Nodes/LoopNode';
|
|
import NormalNode from './components/Nodes/NormalNode';
|
|
import ConditionNode from './components/Nodes/ConditionNode';
|
|
import GroupStartNode from './components/Nodes/GroupStartNode';
|
|
import AddNode from './components/Nodes/AddNode'
|
|
import NoteNode from './components/Nodes/NoteNode';
|
|
import type { PortMetadata, GroupMetadata } from '@antv/x6/lib/model/port';
|
|
import type { ReactShapeConfig } from '@antv/x6-react-shape';
|
|
|
|
import { memoryConfigListUrl } from '@/api/memory'
|
|
import type { NodeLibrary } from './types'
|
|
|
|
/**
|
|
* Workflow node library configuration
|
|
* Defines all available node types, their icons, and configuration schemas
|
|
*/
|
|
export const nodeLibrary: NodeLibrary[] = [
|
|
{
|
|
category: "coreNode",
|
|
nodes: [
|
|
{ type: "start", icon: 'rb:bg-[url("@/assets/images/workflow/start.svg")]',
|
|
config: {
|
|
variables: {
|
|
type: 'define',
|
|
sys: [
|
|
{
|
|
name: "message",
|
|
type: "string",
|
|
readonly: true
|
|
},
|
|
{
|
|
name: "conversation_id",
|
|
type: "string",
|
|
readonly: true
|
|
},
|
|
{
|
|
name: "execution_id",
|
|
type: "string",
|
|
readonly: true
|
|
},
|
|
{
|
|
name: "workspace_id",
|
|
type: "string",
|
|
readonly: true
|
|
},
|
|
{
|
|
name: "user_id",
|
|
type: "string",
|
|
readonly: true
|
|
},
|
|
{
|
|
name: "files",
|
|
type: "array[file]",
|
|
readonly: true
|
|
},
|
|
],
|
|
defaultValue: []
|
|
}
|
|
}
|
|
},
|
|
{
|
|
type: "end", icon: 'rb:bg-[url("@/assets/images/workflow/end.svg")]',
|
|
config: {
|
|
output: {
|
|
type: 'editor'
|
|
}
|
|
}
|
|
},
|
|
// { type: "answer", icon: answerIcon },
|
|
]
|
|
},
|
|
{
|
|
category: "aiAndCognitiveProcessing",
|
|
nodes: [
|
|
{ type: "llm", icon: 'rb:bg-[url("@/assets/images/workflow/llm.svg")]',
|
|
config: {
|
|
model_id: {
|
|
type: 'define',
|
|
params: { type: 'llm,chat' }, // llm/chat
|
|
valueKey: 'id',
|
|
labelKey: 'name',
|
|
},
|
|
temperature: {
|
|
type: 'define',
|
|
max: 2,
|
|
min: 0,
|
|
step: 0.1,
|
|
defaultValue: 0.7
|
|
},
|
|
max_tokens: {
|
|
type: 'define',
|
|
max: 32000,
|
|
min: 256,
|
|
step: 1,
|
|
defaultValue: 2000
|
|
},
|
|
context: {
|
|
type: 'variableList',
|
|
placeholder: 'workflow.config.llm.contextPlaceholder'
|
|
},
|
|
messages: {
|
|
type: 'define',
|
|
defaultValue: [
|
|
{
|
|
role: 'SYSTEM',
|
|
content: undefined,
|
|
readonly: true
|
|
},
|
|
],
|
|
placeholder: 'workflow.config.llm.messagesPlaceholder'
|
|
},
|
|
memory: {
|
|
type: 'memoryConfig',
|
|
defaultValue: {
|
|
enable: false,
|
|
enable_window: false,
|
|
window_size: 20
|
|
}
|
|
},
|
|
vision: {
|
|
type: 'switch'
|
|
},
|
|
vision_input: {
|
|
type: 'variableList',
|
|
onFilterVariableNames: ['sys.files']
|
|
}
|
|
}
|
|
},
|
|
{ type: "knowledge-retrieval", icon: 'rb:bg-[url("@/assets/images/workflow/rag.svg")]',
|
|
config: {
|
|
query: {
|
|
type: 'variableList',
|
|
},
|
|
knowledge_retrieval: {
|
|
type: 'knowledge'
|
|
}
|
|
}
|
|
},
|
|
{ type: "parameter-extractor", icon: 'rb:bg-[url("@/assets/images/workflow/parameter_extraction.svg")]',
|
|
config: {
|
|
model_id: {
|
|
type: 'modelSelect',
|
|
params: { type: 'llm,chat' }, // llm/chat
|
|
},
|
|
text: {
|
|
type: 'variableList',
|
|
filterLoopIterationVars: true,
|
|
placeholder: 'workflow.config.parameter-extractor.textPlaceholder'
|
|
},
|
|
params: {
|
|
type: 'paramList',
|
|
},
|
|
prompt: {
|
|
type: 'messageEditor',
|
|
isArray: false,
|
|
titleVariant: 'borderless',
|
|
placeholder: 'workflow.config.parameter-extractor.promptPlaceholder'
|
|
},
|
|
}
|
|
}
|
|
]
|
|
},
|
|
{
|
|
category: "cognitiveUpgrading",
|
|
nodes: [
|
|
{ type: "memory-read", icon: 'rb:bg-[url("@/assets/images/workflow/memory-read.svg")]',
|
|
config: {
|
|
message: {
|
|
type: 'editor',
|
|
isArray: false
|
|
},
|
|
config_id: {
|
|
type: 'customSelect',
|
|
url: memoryConfigListUrl,
|
|
valueKey: 'config_id',
|
|
labelKey: 'config_name'
|
|
},
|
|
search_switch: {
|
|
type: 'select',
|
|
options: [
|
|
{ value: '0', label: 'memoryConversation.deepThinking' },
|
|
{ value: '1', label: 'memoryConversation.normalReply' },
|
|
{ value: '2', label: 'memoryConversation.quickReply' },
|
|
],
|
|
needTranslation: true
|
|
}
|
|
}
|
|
},
|
|
{ type: "memory-write", icon: 'rb:bg-[url("@/assets/images/workflow/memory-write.svg")]',
|
|
config: {
|
|
message: {
|
|
type: 'editor',
|
|
isArray: false,
|
|
hidden: true,
|
|
},
|
|
messages: {
|
|
type: 'messageEditor',
|
|
defaultValue: [],
|
|
placeholder: 'workflow.config.llm.messagesPlaceholder',
|
|
isArray: true
|
|
},
|
|
config_id: {
|
|
type: 'customSelect',
|
|
url: memoryConfigListUrl,
|
|
valueKey: 'config_id',
|
|
labelKey: 'config_name'
|
|
}
|
|
}
|
|
},
|
|
]
|
|
},
|
|
{
|
|
category: "flowControl",
|
|
nodes: [
|
|
{ type: "if-else", icon: 'rb:bg-[url("@/assets/images/workflow/condition.svg")]',
|
|
config: {
|
|
cases: {
|
|
type: 'caseList',
|
|
defaultValue: [
|
|
{
|
|
logical_operator: 'and',
|
|
expressions: []
|
|
}
|
|
]
|
|
}
|
|
}
|
|
},
|
|
{ type: "question-classifier", icon: 'rb:bg-[url("@/assets/images/workflow/question-classifier.svg")]',
|
|
config: {
|
|
model_id: {
|
|
type: 'modelSelect',
|
|
params: { type: 'llm,chat' }, // llm/chat
|
|
},
|
|
input_variable: {
|
|
type: 'variableList',
|
|
},
|
|
categories: {
|
|
type: 'categoryList',
|
|
defaultValue: [
|
|
{},
|
|
{}
|
|
]
|
|
},
|
|
user_supplement_prompt: {
|
|
type: 'messageEditor',
|
|
isArray: false,
|
|
titleVariant: 'borderless',
|
|
placeholder: 'common.pleaseEnter'
|
|
}
|
|
}
|
|
},
|
|
{ type: "iteration", icon: 'rb:bg-[url("@/assets/images/workflow/iteration.svg")]',
|
|
config: {
|
|
input: {
|
|
type: 'variableList',
|
|
filterNodeTypes: ['knowledge-retrieval', 'iteration', 'loop', 'parameter-extractor', 'code', 'CONVERSATION'],
|
|
filterVariableNames: ['message']
|
|
},
|
|
parallel: {
|
|
type: 'switch',
|
|
defaultValue: false
|
|
},
|
|
parallel_count: {
|
|
type: 'slider',
|
|
min: 1,
|
|
max: 10,
|
|
step: 1,
|
|
defaultValue: 10,
|
|
dependsOn: 'parallel',
|
|
dependsOnValue: true
|
|
},
|
|
flatten: { // Flatten output
|
|
type: 'switch',
|
|
defaultValue: false
|
|
},
|
|
output: {
|
|
type: 'variableList',
|
|
filterChildNodes: true
|
|
},
|
|
output_type: {
|
|
type: 'define',
|
|
}
|
|
},
|
|
},
|
|
{ type: "loop", icon: 'rb:bg-[url("@/assets/images/workflow/loop.svg")]',
|
|
config: {
|
|
cycle_vars: {
|
|
type: 'cycleVarsList',
|
|
defaultValue: []
|
|
},
|
|
condition: {
|
|
type: 'conditionList',
|
|
showLabel: true,
|
|
defaultValue: {
|
|
logical_operator: 'and',
|
|
expressions: []
|
|
}
|
|
},
|
|
max_loop: {
|
|
type: 'slider',
|
|
min: 1,
|
|
max: 100,
|
|
step: 1,
|
|
defaultValue: 10
|
|
},
|
|
}
|
|
},
|
|
{ type: "cycle-start", icon: 'rb:bg-[url("@/assets/images/workflow/start.svg")]'},
|
|
{ type: "break", icon: 'rb:bg-[url("@/assets/images/workflow/break.svg")]'},
|
|
{ type: "var-aggregator", icon: 'rb:bg-[url("@/assets/images/workflow/aggregator.svg")]',
|
|
config: {
|
|
group: {
|
|
type: 'switch',
|
|
defaultValue: false
|
|
},
|
|
group_variables: {
|
|
type: 'groupVariableList',
|
|
defaultValue: [],
|
|
},
|
|
group_type: {
|
|
type: 'define',
|
|
}
|
|
}
|
|
},
|
|
{ type: "assigner", icon: 'rb:bg-[url("@/assets/images/workflow/assigner.svg")]',
|
|
config: {
|
|
assignments: {
|
|
type: 'assignmentList',
|
|
filterLoopIterationVars: true
|
|
}
|
|
}
|
|
},
|
|
]
|
|
},
|
|
{
|
|
category: "externalInteraction",
|
|
nodes: [
|
|
{ type: "http-request", icon: 'rb:bg-[url("@/assets/images/workflow/http_request.svg")]',
|
|
config: {
|
|
method: {
|
|
type: 'select',
|
|
options: [
|
|
{ label: 'GET', value: 'GET' },
|
|
{ label: 'POST', value: 'POST' },
|
|
{ label: 'HEAD', value: 'HEAD' },
|
|
{ label: 'PATCH', value: 'PATCH' },
|
|
{ label: 'PUT', value: 'PUT' },
|
|
{ label: 'DELETE', value: 'DELETE' },
|
|
],
|
|
defaultValue: 'GET'
|
|
},
|
|
url: {
|
|
type: 'messageEditor',
|
|
isArray: false,
|
|
},
|
|
auth: {
|
|
type: 'define',
|
|
defaultValue: {
|
|
auth_type: 'none'
|
|
}
|
|
},
|
|
headers: {
|
|
type: 'define',
|
|
defaultValue: []
|
|
},
|
|
params: {
|
|
type: 'define',
|
|
defaultValue: []
|
|
},
|
|
body: {
|
|
type: 'define',
|
|
defaultValue: {
|
|
'content_type': 'none'
|
|
}
|
|
},
|
|
verify_ssl: {
|
|
type: 'switch',
|
|
defaultValue: false
|
|
},
|
|
timeouts: {
|
|
type: 'define',
|
|
defaultValue: {}
|
|
},
|
|
retry: {
|
|
type: 'switch',
|
|
defaultValue: {
|
|
enable: false
|
|
}
|
|
},
|
|
error_handle: {
|
|
type: 'define',
|
|
defaultValue: {
|
|
method: 'none'
|
|
}
|
|
}
|
|
}
|
|
},
|
|
{ type: "tool", icon: 'rb:bg-[url("@/assets/images/workflow/tools.svg")]',
|
|
config: {
|
|
tool_id: {
|
|
type: 'cascader'
|
|
},
|
|
tool_parameters: {
|
|
type: 'define'
|
|
}
|
|
}
|
|
},
|
|
{ type: "code", icon: 'rb:bg-[url("@/assets/images/workflow/code_execution.svg")]',
|
|
config: {
|
|
input_variables: {
|
|
type: 'inputList',
|
|
defaultValue: [{ name: 'arg1' }, { name: 'arg2' }]
|
|
},
|
|
language: {
|
|
type: 'select',
|
|
defaultValue: 'python3'
|
|
},
|
|
code: {
|
|
type: 'messageEditor',
|
|
isArray: false,
|
|
language: ['python3', 'javascript'],
|
|
titleVariant: 'borderless',
|
|
defaultValue: `def main(arg1: str, arg2: str):
|
|
return {
|
|
"result": arg1 + arg2,
|
|
}`
|
|
},
|
|
output_variables: {
|
|
type: 'outputList',
|
|
defaultValue: [{name: 'result', type: 'string'}]
|
|
},
|
|
}
|
|
},
|
|
{ type: "jinja-render", icon: 'rb:bg-[url("@/assets/images/workflow/template_rendering.svg")]',
|
|
config: {
|
|
mapping: {
|
|
type: 'mappingList',
|
|
defaultValue: [{name: 'arg1'}]
|
|
},
|
|
template: {
|
|
type: 'messageEditor',
|
|
isArray: false,
|
|
language: 'jinja2',
|
|
titleVariant: 'borderless',
|
|
defaultValue: "{{arg1}}"
|
|
},
|
|
}
|
|
},
|
|
{ type: "document-extractor", icon: 'rb:bg-[url("@/assets/images/workflow/document-extractor.svg")]',
|
|
config: {
|
|
file_selector: {
|
|
type: 'variableList',
|
|
placeholder: 'common.pleaseSelect',
|
|
onFilterVariableNames: ['sys.files']
|
|
}
|
|
}
|
|
},
|
|
{ type: "list-operator", icon: 'rb:bg-[url("@/assets/images/workflow/list-operator.svg")]',
|
|
config: {
|
|
input_list: {
|
|
type: 'variableList',
|
|
},
|
|
filter_by: {
|
|
type: 'define',
|
|
defaultValue: {
|
|
enabled: false,
|
|
conditions: [{}]
|
|
}
|
|
},
|
|
order_by: {
|
|
type: 'define',
|
|
defaultValue: {
|
|
"enabled": false,
|
|
"key": "",
|
|
"value": "asc"
|
|
}
|
|
},
|
|
limit: {
|
|
type: 'define',
|
|
defaultValue: {
|
|
"enabled": false,
|
|
"size": 1
|
|
}
|
|
},
|
|
extract_by: {
|
|
type: 'define',
|
|
defaultValue: {
|
|
"enabled": false,
|
|
"serial": ""
|
|
}
|
|
},
|
|
}
|
|
},
|
|
]
|
|
},
|
|
];
|
|
|
|
export const THEME_MAP: Record<string, { outer: string; title: string; bg: string; border: string }> = {
|
|
blue: {
|
|
outer: '#2E90FA',
|
|
title: '#D1E9FF',
|
|
bg: '#EFF8FF',
|
|
border: '#84CAFF',
|
|
},
|
|
cyan: {
|
|
outer: '#06AED4',
|
|
title: '#CFF9FE',
|
|
bg: '#ECFDFF',
|
|
border: '#67E3F9',
|
|
},
|
|
green: {
|
|
outer: '#16B364',
|
|
title: '#D3F8DF',
|
|
bg: '#EDFCF2',
|
|
border: '#73E2A3',
|
|
},
|
|
yellow: {
|
|
outer: '#EAAA08',
|
|
title: '#FEF7C3',
|
|
bg: '#FEFBE8',
|
|
border: '#FDE272',
|
|
},
|
|
pink: {
|
|
outer: '#EE46BC',
|
|
title: '#FCE7F6',
|
|
bg: '#FDF2FA',
|
|
border: '#FAA7E0',
|
|
},
|
|
violet: {
|
|
outer: '#875BF7',
|
|
title: '#ECE9FE',
|
|
bg: '#F5F3FF',
|
|
border: '#C3B5FD',
|
|
},
|
|
}
|
|
|
|
export const notesConfig = {
|
|
type: "notes",
|
|
icon: 'rb:bg-[url("@/assets/images/workflow/unknown.svg")]',
|
|
config: {
|
|
text: {
|
|
type: 'define',
|
|
},
|
|
theme: {
|
|
type: 'define',
|
|
defaultValue: 'blue',
|
|
},
|
|
width: {
|
|
type: 'define',
|
|
width: 240,
|
|
},
|
|
height: {
|
|
type: 'define',
|
|
height: 120,
|
|
},
|
|
author: {
|
|
type: 'define',
|
|
},
|
|
show_author: {
|
|
type: 'define',
|
|
defaultValue: true
|
|
}
|
|
}
|
|
}
|
|
export const unknownNode = {
|
|
type: 'unknown',
|
|
icon: 'rb:bg-[url("@/assets/images/workflow/unknown.svg")]'
|
|
}
|
|
export const noteNode = {
|
|
type: 'notes',
|
|
icon: 'rb:bg-[url("@/assets/images/workflow/unknown.svg")]'
|
|
}
|
|
|
|
export const nodeWidth = 240;
|
|
|
|
export const conditionNodePortItemArgsY = 60;
|
|
export const conditionNodeItemHeight = 26;
|
|
export const conditionNodeHeight = 110;
|
|
/**
|
|
* Node registration library for X6 graph
|
|
* Maps node shapes to their React components
|
|
*/
|
|
export const nodeRegisterLibrary: ReactShapeConfig[] = [
|
|
{
|
|
shape: 'loop-node',
|
|
width: nodeWidth,
|
|
height: 120,
|
|
component: LoopNode,
|
|
},
|
|
{
|
|
shape: 'iteration-node',
|
|
width: nodeWidth,
|
|
height: 120,
|
|
component: LoopNode,
|
|
},
|
|
{
|
|
shape: 'normal-node',
|
|
width: 120,
|
|
height: 40,
|
|
component: NormalNode,
|
|
},
|
|
{
|
|
shape: 'condition-node',
|
|
width: nodeWidth,
|
|
height: conditionNodeHeight,
|
|
component: ConditionNode,
|
|
},
|
|
{
|
|
shape: 'cycle-start',
|
|
width: 36,
|
|
height: 36,
|
|
component: GroupStartNode,
|
|
},
|
|
{
|
|
shape: 'add-node',
|
|
width: 100,
|
|
height: 28,
|
|
component: AddNode,
|
|
},
|
|
{
|
|
shape: 'notes-node',
|
|
width: nodeWidth,
|
|
height: 120,
|
|
component: NoteNode,
|
|
},
|
|
];
|
|
|
|
/**
|
|
* Port configuration interface
|
|
*/
|
|
interface PortsConfig {
|
|
/** Port group metadata */
|
|
groups?: GroupMetadata;
|
|
/** Port item metadata array */
|
|
items?: PortMetadata[];
|
|
}
|
|
|
|
/**
|
|
* Node configuration interface
|
|
*/
|
|
interface NodeConfig {
|
|
/** Node width in pixels */
|
|
width: number;
|
|
/** Node height in pixels */
|
|
height: number;
|
|
/** Node shape type */
|
|
shape: string;
|
|
/** Port configuration */
|
|
ports?: PortsConfig;
|
|
}
|
|
|
|
/** Edge color for normal state */
|
|
export const edge_color = '#D4D5D9';
|
|
/** Edge color for selected state */
|
|
export const edge_selected_color = '#171719'
|
|
export const edge_width = 2;
|
|
/** Port color */
|
|
export const port_color = '#171719'
|
|
/**
|
|
* Unified port markup configuration
|
|
* Defines SVG elements for port rendering
|
|
*/
|
|
export const portMarkup = [
|
|
{
|
|
tagName: 'circle',
|
|
selector: 'body',
|
|
},
|
|
{
|
|
tagName: 'text',
|
|
selector: 'label',
|
|
},
|
|
];
|
|
|
|
/**
|
|
* Unified port attributes configuration
|
|
* Defines visual styling for ports
|
|
*/
|
|
export const portAttrs = {
|
|
body: {
|
|
r: 6,
|
|
magnet: true,
|
|
stroke: port_color,
|
|
strokeWidth: edge_width,
|
|
fill: port_color,
|
|
},
|
|
label: {
|
|
text: '+',
|
|
fontSize: 12,
|
|
fontWeight: 'bold',
|
|
fill: '#FFFFFF',
|
|
textAnchor: 'middle',
|
|
textVerticalAnchor: 'middle',
|
|
pointerEvents: 'none',
|
|
},
|
|
}
|
|
export const portTextAttrs = { fontSize: 12, fill: '#5B6167' }
|
|
/**
|
|
* Port position arguments
|
|
*/
|
|
export const portItemArgsY = 26;
|
|
export const portArgs = { x: nodeWidth, y: portItemArgsY }
|
|
|
|
const defaultPortGroup = {
|
|
position: { name: 'absolute' },
|
|
markup: [
|
|
{ tagName: 'rect', selector: 'body' },
|
|
{ tagName: 'circle', selector: 'hoverBody' },
|
|
{ tagName: 'text', selector: 'label' },
|
|
],
|
|
attrs: {
|
|
body: {
|
|
width: 1,
|
|
height: 8,
|
|
x: 0.75,
|
|
magnet: true,
|
|
stroke: port_color,
|
|
strokeWidth: edge_width,
|
|
fill: port_color,
|
|
},
|
|
hoverBody: {
|
|
r: 6,
|
|
cy: 2,
|
|
magnet: true,
|
|
stroke: port_color,
|
|
strokeWidth: edge_width,
|
|
fill: port_color,
|
|
opacity: 0,
|
|
},
|
|
label: {
|
|
text: '+',
|
|
fontSize: 12,
|
|
fontWeight: 'bold',
|
|
fill: '#FFFFFF',
|
|
textAnchor: 'middle',
|
|
textVerticalAnchor: 'middle',
|
|
pointerEvents: 'none',
|
|
y: '0.15em',
|
|
opacity: 0,
|
|
},
|
|
},
|
|
}
|
|
|
|
const leftPortGroup = {
|
|
position: { name: 'absolute' },
|
|
markup: [{ tagName: 'rect', selector: 'body' }],
|
|
attrs: {
|
|
body: {
|
|
width: 1,
|
|
height: 8,
|
|
x: -1.75,
|
|
y: -4,
|
|
magnet: true,
|
|
stroke: port_color,
|
|
strokeWidth: edge_width,
|
|
fill: port_color,
|
|
},
|
|
},
|
|
}
|
|
|
|
/**
|
|
* Unified port group configuration
|
|
* Defines port positions and attributes for different sides
|
|
*/
|
|
export const defaultAbsolutePortGroups = {
|
|
right: defaultPortGroup,
|
|
left: leftPortGroup,
|
|
}
|
|
/**
|
|
* Default port items for standard nodes
|
|
*/
|
|
export const defaultPortItems = [
|
|
{ group: 'left', args: { x: 0, y: portItemArgsY }, },
|
|
{ group: 'right', args: { x: nodeWidth, y: portItemArgsY }, },
|
|
];
|
|
|
|
/**
|
|
* Graph node library configuration
|
|
* Maps node types to their visual and structural properties
|
|
*/
|
|
export const graphNodeLibrary: Record<string, NodeConfig> = {
|
|
iteration: {
|
|
width: nodeWidth,
|
|
height: 140,
|
|
shape: 'iteration-node',
|
|
ports: {
|
|
groups: defaultAbsolutePortGroups,
|
|
items: defaultPortItems,
|
|
},
|
|
},
|
|
loop: {
|
|
width: nodeWidth,
|
|
height: 140,
|
|
shape: 'loop-node',
|
|
ports: {
|
|
groups: defaultAbsolutePortGroups,
|
|
items: defaultPortItems,
|
|
},
|
|
},
|
|
'if-else': {
|
|
width: nodeWidth,
|
|
height: conditionNodeHeight,
|
|
shape: 'condition-node',
|
|
ports: {
|
|
groups: defaultAbsolutePortGroups,
|
|
items: [
|
|
defaultPortItems[0],
|
|
...(['IF', 'ELSE'].map((_, index) => ({
|
|
group: 'right',
|
|
id: `CASE${index + 1}`,
|
|
args: {
|
|
...portArgs,
|
|
y: portItemArgsY * index + conditionNodePortItemArgsY,
|
|
},
|
|
}))),
|
|
],
|
|
},
|
|
},
|
|
'question-classifier': {
|
|
width: nodeWidth,
|
|
height: conditionNodeHeight,
|
|
shape: 'condition-node',
|
|
ports: {
|
|
groups: defaultAbsolutePortGroups,
|
|
items: [
|
|
defaultPortItems[0],
|
|
...(['分类1', '分类2'].map((_text, index) => ({
|
|
group: 'right',
|
|
id: `CASE${index + 1}`,
|
|
args: {
|
|
...portArgs,
|
|
y: portItemArgsY * index + conditionNodePortItemArgsY,
|
|
},
|
|
}))),
|
|
],
|
|
},
|
|
},
|
|
start: {
|
|
width: nodeWidth,
|
|
height: 76,
|
|
shape: 'normal-node',
|
|
ports: {
|
|
groups: { right: defaultPortGroup},
|
|
items: [defaultPortItems[1]],
|
|
},
|
|
},
|
|
'cycle-start': {
|
|
width: 36,
|
|
height: 36,
|
|
shape: 'cycle-start',
|
|
ports: {
|
|
groups: { right: defaultPortGroup },
|
|
items: [{ group: 'right', args: { x: 36, y: 18 } }],
|
|
},
|
|
},
|
|
'add-node': {
|
|
width: 100,
|
|
height: 28,
|
|
shape: 'add-node',
|
|
ports: {
|
|
groups: { left: leftPortGroup },
|
|
items: [{ group: 'left', args: { x: 0, y: 18 }}],
|
|
},
|
|
},
|
|
default: {
|
|
width: nodeWidth,
|
|
height: 76,
|
|
shape: 'normal-node',
|
|
ports: {
|
|
groups: defaultAbsolutePortGroups,
|
|
items: defaultPortItems,
|
|
},
|
|
},
|
|
cycleStart: {
|
|
width: 36,
|
|
height: 36,
|
|
shape: 'cycle-start',
|
|
ports: {
|
|
groups: { right: defaultPortGroup },
|
|
items: [{ group: 'right', args: { x: 36, y: 18 }}],
|
|
},
|
|
},
|
|
addStart: {
|
|
width: 100,
|
|
height: 28,
|
|
shape: 'add-node',
|
|
ports: {
|
|
groups: { left: leftPortGroup },
|
|
items: [{ group: 'left', args: { x: 0, y: 14 } }],
|
|
},
|
|
},
|
|
break: {
|
|
width: nodeWidth,
|
|
height: 76,
|
|
shape: 'normal-node',
|
|
ports: {
|
|
groups: { left: leftPortGroup },
|
|
items: [defaultPortItems[0]],
|
|
},
|
|
},
|
|
notes: {
|
|
width: nodeWidth,
|
|
height: 120,
|
|
shape: 'notes-node',
|
|
}
|
|
}
|
|
|
|
|
|
/**
|
|
* Output variable configuration interface
|
|
*/
|
|
export interface OutputVariable {
|
|
/** Default output variables */
|
|
default?: Array<{
|
|
name: string;
|
|
type: string;
|
|
}>;
|
|
/** Dynamically defined variable keys */
|
|
define?: string[];
|
|
/** System-level output variables */
|
|
sys?: Array<{
|
|
name: string;
|
|
type: string;
|
|
}>;
|
|
/** Error-related output variables */
|
|
error?: Array<{
|
|
name: string;
|
|
type: string;
|
|
}>;
|
|
}
|
|
|
|
/**
|
|
* Default edge attributes configuration
|
|
* Defines visual styling for edges/connections
|
|
*/
|
|
export const edgeAttrs = {
|
|
attrs: {
|
|
line: {
|
|
stroke: edge_color,
|
|
strokeWidth: edge_width,
|
|
targetMarker: null,
|
|
sourceMarker: null,
|
|
},
|
|
},
|
|
}
|
|
|
|
/**
|
|
* Edge hover tool: circular "+" button shown at midpoint on hover
|
|
*/
|
|
export const edgeHoverTool = {
|
|
name: 'button',
|
|
args: {
|
|
markup: [
|
|
{
|
|
tagName: 'circle',
|
|
selector: 'button',
|
|
attrs: {
|
|
r: 6,
|
|
stroke: port_color,
|
|
strokeWidth: edge_width,
|
|
fill: port_color,
|
|
cursor: 'pointer',
|
|
},
|
|
},
|
|
{
|
|
tagName: 'text',
|
|
textContent: '+',
|
|
selector: 'icon',
|
|
attrs: {
|
|
fontSize: 12,
|
|
fontWeight: 'bold',
|
|
fill: '#FFFFFF',
|
|
textAnchor: 'middle',
|
|
textVerticalAnchor: 'middle',
|
|
pointerEvents: 'none',
|
|
y: '0.3em',
|
|
},
|
|
},
|
|
],
|
|
distance: 0.5,
|
|
offset: { x: 0, y: 0 },
|
|
onClick({ e, cell: edge }: any) {
|
|
e.stopPropagation();
|
|
const graph = edge.model?.graph;
|
|
if (!graph) return;
|
|
const sourceCell = graph.getCellById(edge.getSourceCellId());
|
|
const targetCell = graph.getCellById(edge.getTargetCellId());
|
|
const sourcePort = edge.getSourcePortId();
|
|
const targetPort = edge.getTargetPortId();
|
|
if (!sourceCell || !targetCell) return;
|
|
const rect = (e.target as HTMLElement).getBoundingClientRect();
|
|
const tempDiv = document.createElement('div');
|
|
tempDiv.style.position = 'fixed';
|
|
tempDiv.style.left = rect.left + 'px';
|
|
tempDiv.style.top = rect.top + 'px';
|
|
tempDiv.style.width = '1px';
|
|
tempDiv.style.height = '1px';
|
|
tempDiv.style.zIndex = '9999';
|
|
document.body.appendChild(tempDiv);
|
|
window.dispatchEvent(new CustomEvent('port:click', {
|
|
detail: {
|
|
node: sourceCell,
|
|
port: sourcePort,
|
|
element: tempDiv,
|
|
rect,
|
|
edgeInsertion: { edge, sourceCell, targetCell, sourcePort, targetPort }
|
|
}
|
|
}));
|
|
},
|
|
},
|
|
} |