From 2df3cb30743534706d70cd73e00b882869a1ffdd Mon Sep 17 00:00:00 2001 From: dengqichen Date: Fri, 13 Dec 2024 09:48:04 +0800 Subject: [PATCH] =?UTF-8?q?=E5=A2=9E=E5=8A=A0=E5=B7=A5=E5=85=B7=E6=A0=8F?= =?UTF-8?q?=E6=8F=90=E7=A4=BA=E3=80=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Workflow/Definition/Design/index.tsx | 10 +- .../Definition/Design/utils/validator.ts | 140 ++++++++++++++++++ 2 files changed, 149 insertions(+), 1 deletion(-) create mode 100644 frontend/src/pages/Workflow/Definition/Design/utils/validator.ts diff --git a/frontend/src/pages/Workflow/Definition/Design/index.tsx b/frontend/src/pages/Workflow/Definition/Design/index.tsx index 98001fe2..b5487793 100644 --- a/frontend/src/pages/Workflow/Definition/Design/index.tsx +++ b/frontend/src/pages/Workflow/Definition/Design/index.tsx @@ -7,6 +7,7 @@ import { getDefinitionDetail, saveDefinition } from '../service'; import NodePanel from './components/NodePanel'; import NodeConfigDrawer from './components/NodeConfigModal'; import { NodeDefinition } from './types'; +import { validateWorkflow } from './utils/validator'; import { NODE_REGISTRY_CONFIG, GRID_CONFIG, @@ -208,6 +209,13 @@ const WorkflowDesign: React.FC = () => { if (!graph || !definitionData) return; try { + // 校验流程图 + const validationResult = validateWorkflow(graph); + if (!validationResult.valid) { + message.error(validationResult.message); + return; + } + // 获取所有节点和边的数据 const nodes = graph.getNodes().map(node => { const nodeDefinition = node.getProp('nodeDefinition'); @@ -215,7 +223,7 @@ const WorkflowDesign: React.FC = () => { return { id: node.id, - code: nodeType, // 设置 code 为节点的 type + code: nodeType, type: nodeType, name: node.attr('label/text'), graph: { diff --git a/frontend/src/pages/Workflow/Definition/Design/utils/validator.ts b/frontend/src/pages/Workflow/Definition/Design/utils/validator.ts new file mode 100644 index 00000000..7bf9d925 --- /dev/null +++ b/frontend/src/pages/Workflow/Definition/Design/utils/validator.ts @@ -0,0 +1,140 @@ +import { Graph, Cell } from '@antv/x6'; + +interface ValidationResult { + valid: boolean; + message?: string; +} + +/** + * 校验节点配置 + * @param node 节点 + * @param nodeDefinition 节点定义 + */ +const validateNodeConfig = (node: Cell, nodeDefinition: any): ValidationResult => { + const config = node.getProp('config'); + const configSchema = nodeDefinition?.graphConfig.configSchema; + + if (!config) { + return { + valid: false, + message: `节点 "${node.attr('label/text')}" 未配置` + }; + } + + // 检查必填字段 + if (configSchema?.required) { + for (const field of configSchema.required) { + if (!config[field]) { + const fieldTitle = configSchema.properties[field]?.title || field; + return { + valid: false, + message: `节点 "${node.attr('label/text')}" 的 "${fieldTitle}" 是必填项` + }; + } + } + } + + return { valid: true }; +}; + +/** + * 校验流程图是否为空 + * @param graph 流程图实例 + */ +const validateGraphNotEmpty = (graph: Graph): ValidationResult => { + const nodes = graph.getNodes(); + if (nodes.length === 0) { + return { + valid: false, + message: '流程图中没有任何节点' + }; + } + return { valid: true }; +}; + +/** + * 校验必要节点 + * @param graph 流程图实例 + */ +const validateRequiredNodes = (graph: Graph): ValidationResult => { + const nodes = graph.getNodes(); + + // 检查开始节点 + const hasStartNode = nodes.some(node => node.getProp('type') === 'START_EVENT'); + if (!hasStartNode) { + return { + valid: false, + message: '流程图中必须包含开始节点' + }; + } + + // 检查结束节点 + const hasEndNode = nodes.some(node => node.getProp('type') === 'END_EVENT'); + if (!hasEndNode) { + return { + valid: false, + message: '流程图中必须包含结束节点' + }; + } + + return { valid: true }; +}; + +/** + * 校验节点连接 + * @param graph 流程图实例 + */ +const validateNodeConnections = (graph: Graph): ValidationResult => { + const nodes = graph.getNodes(); + const edges = graph.getEdges(); + + if (edges.length < nodes.length - 1) { + return { + valid: false, + message: '存在未连接的节点,请确保所有节点都已正确连接' + }; + } + + return { valid: true }; +}; + +/** + * 校验所有节点配置 + * @param graph 流程图实例 + */ +const validateAllNodesConfig = (graph: Graph): ValidationResult => { + const nodes = graph.getNodes(); + + for (const node of nodes) { + const nodeDefinition = node.getProp('nodeDefinition'); + const result = validateNodeConfig(node, nodeDefinition); + if (!result.valid) { + return result; + } + } + + return { valid: true }; +}; + +/** + * 校验整个流程图 + * @param graph 流程图实例 + */ +export const validateWorkflow = (graph: Graph): ValidationResult => { + // 按顺序执行所有验证 + const validators = [ + validateGraphNotEmpty, + validateRequiredNodes, + validateAllNodesConfig, + validateNodeConnections + ]; + + for (const validator of validators) { + const result = validator(graph); + if (!result.valid) { + return result; + } + } + + return { valid: true }; +};