feat(web): if-else/question-classifier node port layout update

This commit is contained in:
zhaoying
2026-02-09 18:40:24 +08:00
parent e19d27f640
commit f076199e3f
7 changed files with 188 additions and 128 deletions

View File

@@ -1,3 +1,9 @@
/*
* @Author: ZhaoYing
* @Date: 2026-02-09 18:24:53
* @Last Modified by: ZhaoYing
* @Last Modified time: 2026-02-09 18:24:53
*/
import { type FC } from 'react'
import clsx from 'clsx'
import { useTranslation } from 'react-i18next';
@@ -6,7 +12,7 @@ import { Form, Button, Select, Space, Divider, InputNumber, Radio, type SelectPr
import type { Suggestion } from '../../Editor/plugin/AutocompletePlugin'
import VariableSelect from '../VariableSelect'
import Editor from '../../Editor'
import { edgeAttrs, portArgs } from '../../../constant'
import { edgeAttrs, portTextAttrs, nodeWidth } from '../../../constant'
interface CaseListProps {
value?: Array<{ logical_operator: 'and' | 'or'; expressions: { left: string; operator: string; right: string; input_type?: string; }[] }>;
@@ -52,15 +58,16 @@ const CaseList: FC<CaseListProps> = ({
const { t } = useTranslation();
const form = Form.useFormInstance();
// Update node ports based on case count changes (add/remove cases)
const updateNodePorts = (caseCount: number, removedCaseIndex?: number) => {
if (!selectedNode || !graphRef?.current) return;
// 获取当前端口数量来判断是添加还是删除操作
// Get current port count to determine if it's an add or remove operation
const currentPorts = selectedNode.getPorts().filter((port: any) => port.group === 'right');
const currentCaseCount = currentPorts.length - 1; // 减去ELSE端口
const currentCaseCount = currentPorts.length - 1; // Exclude ELSE port
const isAddingCase = removedCaseIndex === undefined && caseCount > currentCaseCount;
// 保存现有连线信息(包括左侧端口连线)
// Save existing edge connections (including left-side port connections)
const existingEdges = graphRef.current.getEdges().filter((edge: any) =>
edge.getSourceCellId() === selectedNode.id || edge.getTargetCellId() === selectedNode.id
);
@@ -73,7 +80,7 @@ const CaseList: FC<CaseListProps> = ({
isIncoming: edge.getTargetCellId() === selectedNode.id
}));
// 移除所有现有的右侧端口
// Remove all existing right-side ports
const existingPorts = selectedNode.getPorts();
existingPorts.forEach((port: any) => {
if (port.group === 'right') {
@@ -81,43 +88,52 @@ const CaseList: FC<CaseListProps> = ({
}
});
// 计算新的节点高度基础高度88px + 每个额外port增加30px
// Calculate new node height: base height 88px + 30px for each additional port
const baseHeight = 88;
const totalPorts = caseCount + 1; // IF/ELIF + ELSE
const newHeight = baseHeight + (totalPorts - 2) * 30;
selectedNode.prop('size', { width: 240, height: newHeight })
// 添加 IF 端口
selectedNode.prop('size', { width: nodeWidth, height: newHeight })
// Add IF port
selectedNode.addPort({
id: 'CASE1',
group: 'right',
args: portArgs,
attrs: { text: { text: 'IF', fontSize: 12, fill: '#5B6167' }}
});
args: {
x: nodeWidth,
y: 42,
},
attrs: { text: { text: 'IF', ...portTextAttrs } }
})
// 添加 ELIF 端口
// Add ELIF ports
for (let i = 1; i < caseCount; i++) {
selectedNode.addPort({
id: `CASE${i + 1}`,
group: 'right',
args: portArgs,
attrs: { text: { text: 'ELIF', fontSize: 12, fill: '#5B6167' }}
args: {
x: nodeWidth,
y: 30 * i + 42,
},
attrs: { text: { text: 'ELIF', ...portTextAttrs }}
});
}
// 添加 ELSE 端口
// Add ELSE port
selectedNode.addPort({
id: `CASE${caseCount + 1}`,
group: 'right',
args: portArgs,
attrs: { text: { text: 'ELSE', fontSize: 12, fill: '#5B6167' }}
args: {
x: nodeWidth,
y: 30 * caseCount + 42,
},
attrs: { text: { text: 'ELSE', ...portTextAttrs }}
});
// 恢复连线
// Restore edge connections
setTimeout(() => {
edgeConnections.forEach(({ edge, sourcePortId, targetCellId, targetPortId, sourceCellId, isIncoming }: any) => {
// 如果是进入连线(左侧端口),直接恢复
// If it's an incoming connection (left-side port), restore directly
if (isIncoming) {
const sourceCell = graphRef.current?.getCellById(sourceCellId);
if (sourceCell) {
@@ -131,10 +147,10 @@ const CaseList: FC<CaseListProps> = ({
return;
}
// 处理右侧端口连线
// Handle right-side port connections
const originalCaseNumber = parseInt(sourcePortId.match(/CASE(\d+)/)?.[1] || '0');
// 如果是删除操作且是被删除的端口,删除连线
// If it's a remove operation and the port is being removed, delete the connection
if (removedCaseIndex !== undefined && originalCaseNumber === removedCaseIndex + 1) {
graphRef.current?.removeCell(edge);
return;
@@ -142,22 +158,22 @@ const CaseList: FC<CaseListProps> = ({
let newPortId = sourcePortId;
// 如果是删除操作,需要重新映射端口ID
// If it's a remove operation, remap port IDs
if (removedCaseIndex !== undefined) {
if (originalCaseNumber > removedCaseIndex + 1) {
// 被删除端口之后的端口,编号向前移动
// Ports after the removed port, shift numbering forward
newPortId = `CASE${originalCaseNumber - 1}`;
}
// ELSE端口始终映射到新的ELSE端口位置
// ELSE port always maps to the new ELSE port position
else if (originalCaseNumber === currentCaseCount + 1) {
newPortId = `CASE${caseCount + 1}`;
}
} else if (isAddingCase) {
// 如果是添加操作ELSE端口需要重新映射
// If it's an add operation, ELSE port needs to be remapped
if (originalCaseNumber === currentCaseCount + 1) {
newPortId = `CASE${caseCount + 1}`; // 新的ELSE端口
newPortId = `CASE${caseCount + 1}`; // New ELSE port
}
// 新添加的端口不恢复任何连线
// Newly added ports don't restore any connections
}
const newPorts = selectedNode.getPorts();

View File

@@ -1,3 +1,9 @@
/*
* @Author: ZhaoYing
* @Date: 2026-02-09 18:34:33
* @Last Modified by: ZhaoYing
* @Last Modified time: 2026-02-09 18:34:33
*/
import { type FC } from 'react';
import { useTranslation } from 'react-i18next';
import { Button, Form, Space } from 'antd';
@@ -5,7 +11,7 @@ import { Graph, Node } from '@antv/x6';
import Editor from '../../Editor';
import type { Suggestion } from '../../Editor/plugin/AutocompletePlugin'
import { edgeAttrs, portArgs } from '../../../constant'
import { edgeAttrs, portTextAttrs, nodeWidth } from '../../../constant'
interface CategoryListProps {
parentName: string;
@@ -19,10 +25,11 @@ const CategoryList: FC<CategoryListProps> = ({ parentName, selectedNode, graphRe
const form = Form.useFormInstance();
const formValues = Form.useWatch([parentName], form);
// Update node ports based on category count changes (add/remove categories)
const updateNodePorts = (caseCount: number, removedCaseIndex?: number) => {
if (!selectedNode || !graphRef?.current) return;
// 保存现有连线信息(包括左侧端口连线)
// Save existing edge connections (including left-side port connections)
const existingEdges = graphRef.current.getEdges().filter((edge: any) =>
edge.getSourceCellId() === selectedNode.id || edge.getTargetCellId() === selectedNode.id
);
@@ -35,7 +42,7 @@ const CategoryList: FC<CategoryListProps> = ({ parentName, selectedNode, graphRe
isIncoming: edge.getTargetCellId() === selectedNode.id
}));
// 移除所有现有的右侧端口
// Remove all existing right-side ports
const existingPorts = selectedNode.getPorts();
existingPorts.forEach((port: any) => {
if (port.group === 'right') {
@@ -43,28 +50,30 @@ const CategoryList: FC<CategoryListProps> = ({ parentName, selectedNode, graphRe
}
});
// 计算新的节点高度基础高度88px + 每个额外port增加30px
// Calculate new node height: base height 88px + 30px for each additional port
const baseHeight = 88;
const totalPorts = caseCount + 1; // IF/ELIF + ELSE
const newHeight = baseHeight + (totalPorts - 2) * 30;
const newHeight = baseHeight + (caseCount - 2) * 30;
selectedNode.prop('size', { width: 240, height: newHeight < baseHeight ? baseHeight : newHeight })
selectedNode.prop('size', { width: nodeWidth, height: newHeight < baseHeight ? baseHeight : newHeight })
// 添加 分类 端口
// Add category ports
for (let i = 0; i < caseCount; i++) {
selectedNode.addPort({
id: `CASE${i + 1}`,
group: 'right',
args: portArgs,
attrs: { text: { text: `分类${i + 1}`, fontSize: 12, fill: '#5B6167' } }
args: {
x: nodeWidth,
y: 30 * i + 42,
},
attrs: { text: { text: `分类${i + 1}`, ...portTextAttrs } }
});
}
// 恢复连线
// Restore edge connections
setTimeout(() => {
edgeConnections.forEach(({ edge, sourcePortId, targetCellId, targetPortId, sourceCellId, isIncoming }: any) => {
graphRef.current?.removeCell(edge);
// 如果是进入连线(左侧端口),直接恢复
// If it's an incoming connection (left-side port), restore directly
if (isIncoming) {
const sourceCell = graphRef.current?.getCellById(sourceCellId);
if (sourceCell) {
@@ -77,22 +86,22 @@ const CategoryList: FC<CategoryListProps> = ({ parentName, selectedNode, graphRe
return;
}
// 处理右侧端口连线
// Handle right-side port connections
const originalCaseNumber = parseInt(sourcePortId.match(/CASE(\d+)/)?.[1] || '0');
// 如果是被删除的端口,不重新创建连线
// If it's a removed port, don't recreate the connection
if (removedCaseIndex !== undefined && originalCaseNumber === removedCaseIndex + 1) {
return;
}
let newPortId = sourcePortId;
// 如果删除了某个端口,需要重新映射后续端口的ID
// If a port was removed, remap subsequent port IDs
if (removedCaseIndex !== undefined && originalCaseNumber > removedCaseIndex + 1) {
newPortId = `CASE${originalCaseNumber - 1}`;
}
// 检查新端口是否存在
// Check if the new port exists
const newPorts = selectedNode.getPorts();
const matchingPort = newPorts.find((port: any) => port.id === newPortId);

View File

@@ -1,7 +1,14 @@
/*
* @Author: ZhaoYing
* @Date: 2026-02-09 18:35:43
* @Last Modified by: ZhaoYing
* @Last Modified time: 2026-02-09 18:35:43
*/
import { type FC, useRef, useState } from "react";
import { useTranslation } from 'react-i18next'
import { Form, Row, Col, Select, Button, Divider, InputNumber, Switch, Input } from 'antd'
import { CaretDownOutlined, CaretRightOutlined, SettingOutlined } from '@ant-design/icons';
import Editor from '../../Editor'
import type { Suggestion } from '../../Editor/plugin/AutocompletePlugin'
import AuthConfigModal from './AuthConfigModal'
@@ -9,6 +16,7 @@ import type { AuthConfigModalRef, HttpRequestConfigForm } from './types'
import VariableSelect from "../VariableSelect";
import MessageEditor from '../MessageEditor'
import EditableTable from './EditableTable'
import { portTextAttrs } from '../../../constant'
const HttpRequest: FC<{ options: Suggestion[]; selectedNode?: any; graphRef?: any; }> = ({
options,
@@ -32,6 +40,7 @@ const HttpRequest: FC<{ options: Suggestion[]; selectedNode?: any; graphRef?: an
form.setFieldValue(['body', 'data'], undefined)
}
// Handle error handling method change and update node ports accordingly
const handleChangeErrorHandleMethod = (method: string) => {
form.setFieldsValue({
error_handle: {
@@ -42,21 +51,21 @@ const HttpRequest: FC<{ options: Suggestion[]; selectedNode?: any; graphRef?: an
}
})
// 更新节点连接桩
// Update node ports
console.log('handleChangeErrorHandleMethod', selectedNode, graphRef?.current)
if (selectedNode && graphRef?.current) {
const existingPorts = selectedNode.getPorts();
const errorPort = existingPorts.find((port: any) => port.id === 'ERROR');
if (method === 'branch' && !errorPort) {
// 添加异常节点连接桩
// Add error branch port
selectedNode.addPort({
id: 'ERROR',
group: 'right',
attrs: { text: { text: t('workflow.config.http-request.errorBranch'), fontSize: 12, fill: '#5B6167' }}
attrs: { text: { text: t('workflow.config.http-request.errorBranch'), ...portTextAttrs }}
});
} else if (method !== 'branch' && errorPort) {
// 移除异常节点连接桩和相关连线
// Remove error branch port and related edges
const edges = graphRef.current.getEdges().filter((edge: any) =>
edge.getSourceCellId() === selectedNode.id && edge.getSourcePortId() === 'ERROR'
);