From 4fded64d7c63878b004d7fc982dbd23704d3f19b Mon Sep 17 00:00:00 2001 From: dengqichen Date: Wed, 22 Oct 2025 15:50:48 +0800 Subject: [PATCH] 1 --- .../VariableInput/HighlightLayer.tsx | 3 + .../src/components/VariableInput/index.tsx | 8 ++- .../Design/nodes/JenkinsBuildNode.tsx | 6 +- .../Design/nodes/NotificationNode.tsx | 25 ++++++-- .../Design/nodes/components/BaseNode.tsx | 61 +++++++++++++++++-- .../Workflow/Design/utils/dataSourceLoader.ts | 12 +++- 6 files changed, 100 insertions(+), 15 deletions(-) diff --git a/frontend/src/components/VariableInput/HighlightLayer.tsx b/frontend/src/components/VariableInput/HighlightLayer.tsx index b0cef773..eae4a17e 100644 --- a/frontend/src/components/VariableInput/HighlightLayer.tsx +++ b/frontend/src/components/VariableInput/HighlightLayer.tsx @@ -51,6 +51,9 @@ const HighlightLayer: React.FC = ({ value, className }) => textDecorationColor: 'hsl(199 89% 48% / 0.6)', textDecorationThickness: '2px', textUnderlineOffset: '2px', + // 确保垂直对齐 + display: 'inline', + verticalAlign: 'baseline', }} > {match[0]} diff --git a/frontend/src/components/VariableInput/index.tsx b/frontend/src/components/VariableInput/index.tsx index fe9f0319..4df56d70 100644 --- a/frontend/src/components/VariableInput/index.tsx +++ b/frontend/src/components/VariableInput/index.tsx @@ -142,6 +142,8 @@ const VariableInput: React.FC = ({ highlightElement.style.whiteSpace = variant === 'textarea' ? 'pre-wrap' : 'nowrap'; highlightElement.style.wordWrap = 'break-word'; highlightElement.style.overflowWrap = inputStyles.overflowWrap; + highlightElement.style.verticalAlign = inputStyles.verticalAlign; + highlightElement.style.boxSizing = inputStyles.boxSizing; }; // 同步滚动位置(仅 textarea) @@ -443,9 +445,13 @@ const VariableInput: React.FC = ({ className="absolute inset-0 pointer-events-none" style={{ overflow: 'hidden', + display: variant === 'input' ? 'flex' : 'block', + alignItems: variant === 'input' ? 'center' : 'flex-start', }} > - +
+ +
)} diff --git a/frontend/src/pages/Workflow/Design/nodes/JenkinsBuildNode.tsx b/frontend/src/pages/Workflow/Design/nodes/JenkinsBuildNode.tsx index 922ad405..43c4f888 100644 --- a/frontend/src/pages/Workflow/Design/nodes/JenkinsBuildNode.tsx +++ b/frontend/src/pages/Workflow/Design/nodes/JenkinsBuildNode.tsx @@ -68,12 +68,12 @@ export const JenkinsBuildNodeDefinition: ConfigurableNodeDefinition = { inputMappingSchema: { type: "object", title: "输入", - description: "从上游节点接收的数据映射配置", + description: "当前节点所需数据配置", properties: { jenkinsServerId: { type: "number", - title: "Jenkins服务器", - description: "选择要使用的Jenkins服务器", + title: "服务器", + description: "选择要使用的服务器", 'x-dataSource': DataSourceType.JENKINS_SERVERS }, project: { diff --git a/frontend/src/pages/Workflow/Design/nodes/NotificationNode.tsx b/frontend/src/pages/Workflow/Design/nodes/NotificationNode.tsx index e9ae1c48..c82f8469 100644 --- a/frontend/src/pages/Workflow/Design/nodes/NotificationNode.tsx +++ b/frontend/src/pages/Workflow/Design/nodes/NotificationNode.tsx @@ -1,4 +1,5 @@ import {ConfigurableNodeDefinition, NodeType, NodeCategory} from './types'; +import {DataSourceType} from "@/pages/Workflow/Design/utils/dataSourceLoader.ts"; /** * 通知节点定义 @@ -60,14 +61,28 @@ export const NotificationNodeDefinition: ConfigurableNodeDefinition = { title: "节点描述", description: "节点的详细说明", default: "发送通知消息到指定渠道" - }, + } + }, + required: ["nodeName", "nodeCode", "notificationType", "title", "content"] + }, + inputMappingSchema: { + type: "object", + title: "输入", + description: "当前节点所需数据配置", + properties: { + // notificationType: { + // type: "string", + // title: "通知类型", + // description: "选择通知发送的渠道", + // enum: ["EMAIL", "DINGTALK", "WECHAT_WORK", "SMS"], + // enumNames: ["邮件", "钉钉", "企业微信", "短信"], + // default: "EMAIL" + // }, notificationType: { type: "string", title: "通知类型", description: "选择通知发送的渠道", - enum: ["EMAIL", "DINGTALK", "WECHAT_WORK", "SMS"], - enumNames: ["邮件", "钉钉", "企业微信", "短信"], - default: "EMAIL" + 'x-dataSource': DataSourceType.NOTIFICATION_CHANNEL_TYPES }, title: { type: "string", @@ -83,7 +98,7 @@ export const NotificationNodeDefinition: ConfigurableNodeDefinition = { default: "" } }, - required: ["nodeName", "nodeCode", "notificationType", "title", "content"] + required: ["jenkinsServerId"] }, outputs: [{ name: "status", diff --git a/frontend/src/pages/Workflow/Design/nodes/components/BaseNode.tsx b/frontend/src/pages/Workflow/Design/nodes/components/BaseNode.tsx index 6ec8fe14..5ea50c51 100644 --- a/frontend/src/pages/Workflow/Design/nodes/components/BaseNode.tsx +++ b/frontend/src/pages/Workflow/Design/nodes/components/BaseNode.tsx @@ -2,6 +2,7 @@ import React from 'react'; import { Handle, Position, NodeProps } from '@xyflow/react'; import type { FlowNodeData } from '../../types'; import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card'; +import { isConfigurableNode } from '../types'; /** * BaseNode - shadcn/ui 风格节点 @@ -17,6 +18,52 @@ const BaseNode: React.FC = ({ data, selected }) => { const config = definition.renderConfig; + // 渲染输入字段标签(来自 inputMappingSchema) + const renderInputSection = () => { + if (!isConfigurableNode(definition) || !definition.inputMappingSchema) { + return null; + } + + const schema = definition.inputMappingSchema; + + // 获取所有定义的输入字段(从 schema) + if (!schema.properties) { + return null; + } + + const allInputs = Object.keys(schema.properties).map(key => { + const fieldSchema = schema.properties![key]; + return { + key, + title: fieldSchema.title || key, + description: fieldSchema.description, + }; + }); + + if (allInputs.length === 0) { + return null; + } + + return ( +
+ {/* 输入标签 - 靠左 */} +
输入
+ {/* 输入字段标签 */} +
+ {allInputs.map((input, index) => ( + + {input.title} + + ))} +
+
+ ); + }; + // 渲染输出字段标签 const renderOutputSection = () => { if (!nodeData.outputs || nodeData.outputs.length === 0) { @@ -32,9 +79,9 @@ const BaseNode: React.FC = ({ data, selected }) => { - {output.name} + {output.title || output.name} ))} @@ -150,9 +197,13 @@ const BaseNode: React.FC = ({ data, selected }) => { - {/* 输出部分 */} - {renderOutputSection() && ( - + {/* 输入/输出部分 */} + {(renderInputSection() || renderOutputSection()) && ( + + {/* 输入部分 */} + {renderInputSection()} + + {/* 输出部分 */} {renderOutputSection()} )} diff --git a/frontend/src/pages/Workflow/Design/utils/dataSourceLoader.ts b/frontend/src/pages/Workflow/Design/utils/dataSourceLoader.ts index 74665b35..510333e5 100644 --- a/frontend/src/pages/Workflow/Design/utils/dataSourceLoader.ts +++ b/frontend/src/pages/Workflow/Design/utils/dataSourceLoader.ts @@ -7,7 +7,8 @@ export enum DataSourceType { JENKINS_SERVERS = 'JENKINS_SERVERS', K8S_CLUSTERS = 'K8S_CLUSTERS', GIT_REPOSITORIES = 'GIT_REPOSITORIES', - DOCKER_REGISTRIES = 'DOCKER_REGISTRIES' + DOCKER_REGISTRIES = 'DOCKER_REGISTRIES', + NOTIFICATION_CHANNEL_TYPES = 'NOTIFICATION_CHANNEL_TYPES' } /** @@ -44,6 +45,15 @@ export const DATA_SOURCE_REGISTRY: Record = { })); } }, + [DataSourceType.NOTIFICATION_CHANNEL_TYPES]: { + url: '/api/v1/notification-channel/types', + transform: (data: any[]) => { + return data.map((item: any) => ({ + label: `${item.label}`, + value: item.code + })); + } + }, [DataSourceType.K8S_CLUSTERS]: { url: '/api/v1/k8s-cluster/list', params: { enabled: true },