1
This commit is contained in:
parent
313307a19d
commit
80ad106934
@ -1,47 +1,10 @@
|
||||
import React, { useState, useRef, useMemo, useEffect } from 'react';
|
||||
import { Command, CommandEmpty, CommandGroup, CommandItem, CommandList } from '@/components/ui/command';
|
||||
import { Input } from '@/components/ui/input';
|
||||
import { Textarea } from '@/components/ui/textarea';
|
||||
import type { VariableInputProps } from './types';
|
||||
import { detectTrigger, insertVariable, filterVariables } from './utils';
|
||||
import { collectNodeVariables, groupVariablesByNode } from '@/utils/workflow/collectNodeVariables';
|
||||
|
||||
/**
|
||||
* 高亮渲染 ${} 变量
|
||||
*/
|
||||
const highlightVariables = (text: string): React.ReactNode[] => {
|
||||
const regex = /\$\{([^}]+)\}/g;
|
||||
const parts: React.ReactNode[] = [];
|
||||
let lastIndex = 0;
|
||||
let match;
|
||||
|
||||
while ((match = regex.exec(text)) !== null) {
|
||||
// 添加变量前的文本
|
||||
if (match.index > lastIndex) {
|
||||
parts.push(text.substring(lastIndex, match.index));
|
||||
}
|
||||
|
||||
// 添加高亮的变量
|
||||
parts.push(
|
||||
<span
|
||||
key={match.index}
|
||||
className="inline-block px-1.5 py-0.5 bg-blue-100 dark:bg-blue-900/30 text-blue-700 dark:text-blue-300 rounded font-mono text-sm border border-blue-200 dark:border-blue-800"
|
||||
>
|
||||
${`{${match[1]}}`}
|
||||
</span>
|
||||
);
|
||||
|
||||
lastIndex = match.index + match[0].length;
|
||||
}
|
||||
|
||||
// 添加剩余文本
|
||||
if (lastIndex < text.length) {
|
||||
parts.push(text.substring(lastIndex));
|
||||
}
|
||||
|
||||
return parts.length > 0 ? parts : [text];
|
||||
};
|
||||
|
||||
/**
|
||||
* 变量输入组件
|
||||
* 支持在输入 ${ 时自动提示可用变量
|
||||
@ -115,15 +78,9 @@ const VariableInput: React.FC<VariableInputProps> = ({
|
||||
|
||||
// 插入变量
|
||||
const handleSelectVariable = (nodeName: string, fieldName: string) => {
|
||||
console.log('🎯 handleSelectVariable 被调用:', { nodeName, fieldName, value, triggerInfo });
|
||||
|
||||
if (!inputRef.current) {
|
||||
console.error('❌ inputRef.current 不存在');
|
||||
return;
|
||||
}
|
||||
if (!inputRef.current) return;
|
||||
|
||||
const cursorPos = inputRef.current.selectionStart || 0;
|
||||
console.log('📍 当前光标位置:', cursorPos);
|
||||
|
||||
// 使用工具函数插入变量
|
||||
const { newText, newCursorPos } = insertVariable(
|
||||
@ -134,8 +91,6 @@ const VariableInput: React.FC<VariableInputProps> = ({
|
||||
fieldName
|
||||
);
|
||||
|
||||
console.log('✅ 插入结果:', { newText, newCursorPos });
|
||||
|
||||
// 更新值
|
||||
onChange(newText);
|
||||
|
||||
@ -147,7 +102,6 @@ const VariableInput: React.FC<VariableInputProps> = ({
|
||||
if (inputRef.current) {
|
||||
inputRef.current.focus();
|
||||
inputRef.current.setSelectionRange(newCursorPos, newCursorPos);
|
||||
console.log('✅ 焦点已恢复,光标已设置');
|
||||
}
|
||||
}, 0);
|
||||
};
|
||||
@ -200,10 +154,7 @@ const VariableInput: React.FC<VariableInputProps> = ({
|
||||
<div
|
||||
key={`${variable.nodeId}.${variable.fieldName}`}
|
||||
className="flex items-center justify-between px-3 py-2 cursor-pointer hover:bg-accent rounded-sm transition-colors"
|
||||
onClick={() => {
|
||||
console.log('点击变量:', variable.nodeName, variable.fieldName);
|
||||
handleSelectVariable(variable.nodeName, variable.fieldName);
|
||||
}}
|
||||
onClick={() => handleSelectVariable(variable.nodeName, variable.fieldName)}
|
||||
>
|
||||
<span className="font-mono text-sm">{variable.fieldName}</span>
|
||||
<span className="ml-auto text-xs text-muted-foreground">{variable.fieldType}</span>
|
||||
@ -216,28 +167,20 @@ const VariableInput: React.FC<VariableInputProps> = ({
|
||||
);
|
||||
};
|
||||
|
||||
// 检测是否有变量需要高亮
|
||||
const hasVariables = value && /\$\{[^}]+\}/.test(value);
|
||||
|
||||
return (
|
||||
<div ref={containerRef} className="relative space-y-2">
|
||||
<div ref={containerRef} className="relative">
|
||||
{/* 输入框 */}
|
||||
{renderInput()}
|
||||
|
||||
{/* 变量高亮预览 */}
|
||||
{hasVariables && !showSuggestions && (
|
||||
<div className="p-2 bg-muted/30 rounded-md border border-border text-sm">
|
||||
<div className="text-xs text-muted-foreground mb-1">变量预览:</div>
|
||||
<div className="break-words leading-relaxed">
|
||||
{highlightVariables(value)}
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* 变量提示弹窗 - 绝对定位 */}
|
||||
{/* 变量提示弹窗 - 绝对定位,使用更高的 z-index */}
|
||||
{showSuggestions && (
|
||||
<div
|
||||
className="absolute top-full left-0 w-full mt-2 z-50"
|
||||
className="fixed mt-2 z-[9999]"
|
||||
style={{
|
||||
top: inputRef.current ? inputRef.current.getBoundingClientRect().bottom + window.scrollY + 8 : 0,
|
||||
left: inputRef.current ? inputRef.current.getBoundingClientRect().left + window.scrollX : 0,
|
||||
width: inputRef.current ? inputRef.current.getBoundingClientRect().width : 'auto',
|
||||
}}
|
||||
>
|
||||
<div className="w-full max-w-[500px] bg-popover text-popover-foreground rounded-md border shadow-lg">
|
||||
{renderSuggestions()}
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
import { ConfigurableNodeDefinition, NodeType, NodeCategory } from './types';
|
||||
import {ConfigurableNodeDefinition, NodeType, NodeCategory} from './types';
|
||||
|
||||
/**
|
||||
* 通知节点定义
|
||||
@ -14,7 +14,7 @@ export const NotificationNodeDefinition: ConfigurableNodeDefinition = {
|
||||
// 渲染配置
|
||||
renderConfig: {
|
||||
shape: 'rounded-rect',
|
||||
size: { width: 120, height: 60 },
|
||||
size: {width: 120, height: 60},
|
||||
icon: {
|
||||
type: 'emoji',
|
||||
content: '🔔',
|
||||
@ -85,35 +85,14 @@ export const NotificationNodeDefinition: ConfigurableNodeDefinition = {
|
||||
},
|
||||
required: ["nodeName", "nodeCode", "notificationType", "title", "content", "recipients"]
|
||||
},
|
||||
|
||||
// 输入映射 Schema(可以引用上游节点的输出)
|
||||
inputMappingSchema: {
|
||||
type: "object",
|
||||
title: "输入映射",
|
||||
description: "配置从上游节点获取的数据",
|
||||
properties: {
|
||||
dynamicTitle: {
|
||||
outputs: [{
|
||||
name: "status",
|
||||
title: "执行状态",
|
||||
type: "string",
|
||||
title: "动态标题",
|
||||
description: "使用上游节点输出动态设置标题,如 ${upstream.buildStatus}",
|
||||
default: ""
|
||||
},
|
||||
dynamicContent: {
|
||||
type: "string",
|
||||
title: "动态内容",
|
||||
description: "使用上游节点输出动态设置内容,如 构建结果: ${upstream.buildStatus}",
|
||||
format: "textarea",
|
||||
default: ""
|
||||
},
|
||||
dynamicRecipients: {
|
||||
type: "string",
|
||||
title: "动态收件人",
|
||||
description: "使用上游节点输出动态设置收件人",
|
||||
default: ""
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ✅ 通知节点没有输出能力(不定义 outputs 字段)
|
||||
enum: ["SUCCESS", "FAILURE"],
|
||||
description: "执行的结果状态",
|
||||
example: "SUCCESS",
|
||||
required: true
|
||||
}]
|
||||
};
|
||||
|
||||
|
||||
Loading…
Reference in New Issue
Block a user