diff --git a/frontend/src/pages/Workflow/Design/nodes/NotificationNode.tsx b/frontend/src/pages/Workflow/Design/nodes/NotificationNode.tsx new file mode 100644 index 00000000..7d2dfe33 --- /dev/null +++ b/frontend/src/pages/Workflow/Design/nodes/NotificationNode.tsx @@ -0,0 +1,125 @@ +import { ConfigurableNodeDefinition, NodeType, NodeCategory } from './types'; + +/** + * 通知节点定义 + * 用于发送各种类型的通知(邮件、钉钉、企业微信等) + */ +export const NotificationNodeDefinition: ConfigurableNodeDefinition = { + nodeCode: "NOTIFICATION", + nodeName: "通知", + nodeType: NodeType.NOTIFICATION, + category: NodeCategory.TASK, + description: "发送通知消息到指定渠道", + + // 渲染配置 + renderConfig: { + shape: 'rounded-rect', + size: { width: 120, height: 60 }, + icon: { + type: 'emoji', + content: '🔔', + size: 24 + }, + theme: { + primary: '#f59e0b', + secondary: '#d97706', + selectedBorder: '#3b82f6', + hoverBorder: '#f59e0b', + gradient: ['#ffffff', '#fef3c7'] + }, + handles: { + input: true, // 有输入 + output: false // 无输出 + }, + features: { + showBadge: true, + showHoverMenu: true + } + }, + + // 基本配置 Schema + configSchema: { + type: "object", + title: "基本配置", + description: "通知节点的基本配置信息", + properties: { + nodeName: { + type: "string", + title: "节点名称", + description: "节点在流程图中显示的名称", + default: "通知" + }, + nodeCode: { + type: "string", + title: "节点编码", + description: "节点的唯一标识符", + default: "NOTIFICATION" + }, + description: { + type: "string", + title: "节点描述", + description: "节点的详细说明", + default: "发送通知消息到指定渠道" + }, + notificationType: { + type: "string", + title: "通知类型", + description: "选择通知发送的渠道", + enum: ["EMAIL", "DINGTALK", "WECHAT_WORK", "SMS"], + enumNames: ["邮件", "钉钉", "企业微信", "短信"], + default: "EMAIL" + }, + title: { + type: "string", + title: "通知标题", + description: "通知消息的标题", + default: "工作流通知" + }, + content: { + type: "string", + title: "通知内容", + description: "通知消息的正文内容,支持变量表达式", + format: "textarea", + default: "" + }, + recipients: { + type: "string", + title: "收件人", + description: "多个收件人用逗号分隔,支持变量表达式", + default: "" + } + }, + required: ["nodeName", "nodeCode", "notificationType", "title", "content", "recipients"] + }, + + // 输入映射 Schema(可以引用上游节点的输出) + inputMappingSchema: { + type: "object", + title: "输入映射", + description: "配置从上游节点获取的数据", + properties: { + dynamicTitle: { + type: "string", + title: "动态标题", + description: "使用上游节点输出动态设置标题,如 ${upstream.buildStatus}", + default: "" + }, + dynamicContent: { + type: "string", + title: "动态内容", + description: "使用上游节点输出动态设置内容,如 构建结果: ${upstream.buildStatus}", + format: "textarea", + default: "" + }, + dynamicRecipients: { + type: "string", + title: "动态收件人", + description: "使用上游节点输出动态设置收件人", + default: "" + } + } + } + + // ✅ 通知节点没有输出能力(不定义 outputs 字段) +}; + diff --git a/frontend/src/pages/Workflow/Design/nodes/index.ts b/frontend/src/pages/Workflow/Design/nodes/index.ts index 62c39120..e72fa9ea 100644 --- a/frontend/src/pages/Workflow/Design/nodes/index.ts +++ b/frontend/src/pages/Workflow/Design/nodes/index.ts @@ -8,6 +8,7 @@ import BaseNode from './components/BaseNode'; import { StartEventNodeDefinition } from './StartEventNode'; import { EndEventNodeDefinition } from './EndEventNode'; import { JenkinsBuildNodeDefinition } from './JenkinsBuildNode'; +import { NotificationNodeDefinition } from './NotificationNode'; import type { WorkflowNodeDefinition } from './types'; /** @@ -17,6 +18,7 @@ export const NODE_DEFINITIONS: WorkflowNodeDefinition[] = [ StartEventNodeDefinition, EndEventNodeDefinition, JenkinsBuildNodeDefinition, + NotificationNodeDefinition, ]; /** @@ -27,6 +29,7 @@ export const nodeTypes = { START_EVENT: BaseNode, END_EVENT: BaseNode, JENKINS_BUILD: BaseNode, + NOTIFICATION: BaseNode, }; /** @@ -40,6 +43,7 @@ export { StartEventNodeDefinition, EndEventNodeDefinition, JenkinsBuildNodeDefinition, + NotificationNodeDefinition, }; // 导出类型 diff --git a/frontend/src/pages/Workflow/Design/nodes/types.ts b/frontend/src/pages/Workflow/Design/nodes/types.ts index 9d1bb068..72eec540 100644 --- a/frontend/src/pages/Workflow/Design/nodes/types.ts +++ b/frontend/src/pages/Workflow/Design/nodes/types.ts @@ -15,6 +15,7 @@ export enum NodeType { SCRIPT_TASK = 'SCRIPT_TASK', DEPLOY_NODE = 'DEPLOY_NODE', JENKINS_BUILD = 'JENKINS_BUILD', + NOTIFICATION = 'NOTIFICATION', GATEWAY_NODE = 'GATEWAY_NODE', SUB_PROCESS = 'SUB_PROCESS', CALL_ACTIVITY = 'CALL_ACTIVITY' @@ -29,6 +30,7 @@ export const NODE_CATEGORY_MAP: Record = { [NodeType.SCRIPT_TASK]: NodeCategory.TASK, [NodeType.DEPLOY_NODE]: NodeCategory.TASK, [NodeType.JENKINS_BUILD]: NodeCategory.TASK, + [NodeType.NOTIFICATION]: NodeCategory.TASK, [NodeType.GATEWAY_NODE]: NodeCategory.GATEWAY, [NodeType.SUB_PROCESS]: NodeCategory.CONTAINER, [NodeType.CALL_ACTIVITY]: NodeCategory.CONTAINER,