diff --git a/frontend/src/pages/Workflow/Definition/Design/components/ExpressionModal.tsx b/frontend/src/pages/Workflow/Definition/Design/components/ExpressionModal.tsx new file mode 100644 index 00000000..839bb92c --- /dev/null +++ b/frontend/src/pages/Workflow/Definition/Design/components/ExpressionModal.tsx @@ -0,0 +1,93 @@ +import React, { useState } from 'react'; +import { Modal, Form, Input, InputNumber, Radio } from 'antd'; +import { Edge } from '@antv/x6'; +import { ConditionType, EdgeCondition } from '../types'; + +interface ExpressionModalProps { + visible: boolean; + edge: Edge; + onOk: (condition: EdgeCondition) => void; + onCancel: () => void; +} + +const ExpressionModal: React.FC = ({ + visible, + edge, + onOk, + onCancel +}) => { + const [form] = Form.useForm(); + const currentCondition = edge.getProp('condition') as EdgeCondition; + + const handleOk = async () => { + try { + const values = await form.validateFields(); + onOk(values); + } catch (error) { + console.error('表单验证失败:', error); + } + }; + + return ( + +
+ + + 表达式 + 默认路径 + + + + prevValues.type !== currentValues.type} + > + {({ getFieldValue }) => { + const type = getFieldValue('type'); + return type === 'EXPRESSION' ? ( + + + + ) : null; + }} + + + + + +
+
+ ); +}; + +export default ExpressionModal; \ No newline at end of file diff --git a/frontend/src/pages/Workflow/Definition/Design/index.tsx b/frontend/src/pages/Workflow/Definition/Design/index.tsx index 0ed011e2..3bd60e17 100644 --- a/frontend/src/pages/Workflow/Definition/Design/index.tsx +++ b/frontend/src/pages/Workflow/Definition/Design/index.tsx @@ -44,6 +44,8 @@ import { } from './constants'; import './index.less'; import {NodeDefinitionResponse, NodeDesignDataResponse} from "@/pages/Workflow/NodeDesign/types"; +import ExpressionModal from './components/ExpressionModal'; +import { EdgeCondition } from './types'; const WorkflowDesign: React.FC = () => { const {id} = useParams<{ id: string }>(); @@ -60,6 +62,8 @@ const WorkflowDesign: React.FC = () => { const [isNodeDefinitionsLoaded, setIsNodeDefinitionsLoaded] = useState(false); const [forceUpdate, setForceUpdate] = useState(false); const [scale, setScale] = useState(1); + const [expressionModalVisible, setExpressionModalVisible] = useState(false); + const [selectedEdge, setSelectedEdge] = useState(null); // 初始化图形 const initGraph = () => { @@ -531,7 +535,7 @@ const WorkflowDesign: React.FC = () => { // 节点点击事件 graph.on('node:click', ({node}) => { - // ��取当前选中的节点 + // 取当前选中的节点 const selectedNode = graph.getSelectedCells()[0]; // 如果有其他节点被选中,恢复其样式 @@ -867,6 +871,15 @@ const WorkflowDesign: React.FC = () => { port.setAttribute('style', 'visibility: hidden'); }); }); + + // 添加边的双击事件 + graph.on('edge:dblclick', ({ edge }) => { + const sourceNode = graph.getCellById(edge.getSourceCellId()); + if (sourceNode.getProp('nodeType') === 'GATEWAY_NODE') { + setSelectedEdge(edge); + setExpressionModalVisible(true); + } + }); }; // 处理复制操作 @@ -893,7 +906,7 @@ const WorkflowDesign: React.FC = () => { message.success('已剪切'); }; - // 处理粘贴操��� + // 处理粘贴操作 const handlePaste = () => { if (!graph) return; if (graph.isClipboardEmpty()) { @@ -962,7 +975,7 @@ const WorkflowDesign: React.FC = () => { return port?.id; }; - // 获取源节点的输出端口(一定���out组) + // 获取源节点的输出端口(一定是out组) const sourcePort = getPortByGroup(sourceNode, 'out'); // 获取目标节点的输入端口(一定是in组) @@ -1123,48 +1136,35 @@ const WorkflowDesign: React.FC = () => { } // 获取所有节点和边的数据 - const nodes = graph.getNodes().map(node => { - const nodeType = node.getProp('nodeType'); - const graphData = node.getProp('graph') || {}; - const position = node.getPosition(); - const { - uiVariables, - panelVariables, - localVariables, - formVariablesSchema, - ...rest - } = graphData; - return { - id: node.id, - nodeCode: nodeType, - nodeType: nodeType, - nodeName: node.attr('label/text'), - uiVariables: { - ...uiVariables, - position: position - }, - panelVariables, - localVariables, - formVariablesSchema - }; - }); - - const edges = graph.getEdges().map(edge => ({ - id: edge.id, - from: edge.getSourceCellId(), - to: edge.getTargetCellId(), - name: edge.getLabels()?.[0]?.attrs?.label?.text || '', - config: { - type: 'sequence' - } + const nodes = graph.getNodes().map(node => ({ + id: node.id, + nodeCode: node.getProp('nodeType'), + nodeType: node.getProp('nodeType'), + nodeName: node.attr('label/text'), + uiVariables: { + ...node.getProp('graph')?.uiVariables, + position: node.getPosition() + }, + panelVariables: node.getProp('graph')?.panelVariables, + localVariables: node.getProp('graph')?.localVariables, + formVariablesSchema: node.getProp('graph')?.formVariablesSchema })); - // 收集并合并所有节点的 formVariablesSchema - const allFormSchemas = nodes - .map(node => node.formVariablesSchema) - .filter(schema => schema); // 过滤掉空值 - - const mergedFormSchema = mergeFormVariablesSchemas(allFormSchemas); + const edges = graph.getEdges().map(edge => { + const sourceNode = graph.getCellById(edge.getSourceCellId()); + const condition = edge.getProp('condition'); + + return { + id: edge.id, + from: edge.getSourceCellId(), + to: edge.getTargetCellId(), + name: edge.getLabels()?.[0]?.attrs?.label?.text || '', + config: { + type: 'sequence', + condition: condition || undefined + } + }; + }); // 构建保存数据 const saveData = { @@ -1172,36 +1172,56 @@ const WorkflowDesign: React.FC = () => { graph: { nodes, edges - }, - formVariablesSchema: mergedFormSchema + } }; // 调用保存接口 await saveDefinition(saveData); - // 使用 Modal.confirm 显示操作选择 - Modal.confirm({ - title: '保存成功', - content: '流程设计已保存成功,请选择下一步操作', - okText: '继续设计', - cancelText: '返回列表', - onOk: () => { - // 重新加载设计数据 - if (id) { - loadDefinitionDetail(graph, id); - } - }, - onCancel: () => { - // 返回列表页 - navigate('/workflow/definition'); - } - }); + message.success('保存成功'); } catch (error) { console.error('保存流程失败:', error); message.error('保存流程失败'); } }; + // 处理条件更新 + const handleConditionUpdate = (condition: EdgeCondition) => { + if (!selectedEdge) return; + + // 更新边的属性 + selectedEdge.setProp('condition', condition); + + // 更新边的标签显示 + const labelText = condition.type === 'EXPRESSION' + ? condition.expression + : '默认路径'; + + selectedEdge.setLabels([{ + attrs: { + label: { + text: labelText, + fill: '#333', + fontSize: 12 + }, + rect: { + fill: '#fff', + stroke: '#ccc', + rx: 3, + ry: 3, + padding: 5 + } + }, + position: { + distance: 0.5, + offset: 0 + } + }]); + + setExpressionModalVisible(false); + setSelectedEdge(null); + }; + return (
@@ -1375,6 +1395,17 @@ const WorkflowDesign: React.FC = () => { onOk={handleNodeConfigUpdate} /> )} + {selectedEdge && ( + { + setExpressionModalVisible(false); + setSelectedEdge(null); + }} + /> + )}
); };