2025-05-02 17:31:33 +08:00

70 lines
3.2 KiB
TypeScript

// File: frontend/app/workflow/components/ChatInputNode.tsx (新建)
// Description: 自定义 ChatInput 节点
import React, { memo, useCallback, ChangeEvent } from 'react';
import { Handle, Position, useReactFlow, Node } from 'reactflow';
import { MessageCircleQuestion } from 'lucide-react'; // 使用合适的图标
import { Label } from "@/components/ui/label";
import { Textarea } from "@/components/ui/textarea";
import type { ChatInputNodeData, CustomNodeProps } from './types';
const ChatInputNodeComponent = ({ id, data, isConnectable }: CustomNodeProps<ChatInputNodeData>) => {
const { setNodes } = useReactFlow<ChatInputNodeData>();
const handleTextChange = useCallback((event: ChangeEvent<HTMLTextAreaElement>) => {
const newText = event.target.value;
setNodes((nds: Node<ChatInputNodeData>[]) =>
nds.map((node) => {
if (node.id === id) {
return { ...node, data: { ...node.data, text: newText } };
}
return node;
})
);
}, [id, setNodes]);
return (
<div className="react-flow__node-genericNode nopan bg-gray-50 dark:bg-gray-800 border border-gray-300 dark:border-gray-700 rounded-lg shadow-lg w-96"> {/* 调整宽度 */}
{/* 节点头部 */}
<div className="bg-gray-100 dark:bg-gray-700 p-3 border-b border-gray-300 dark:border-gray-600">
<div className="flex items-center gap-2">
<MessageCircleQuestion size={18} className="text-gray-700 dark:text-gray-300" />
<strong className="text-gray-800 dark:text-gray-200">Chat Input</strong>
</div>
<p className="text-xs text-gray-600 dark:text-gray-400 mt-1"> Playground </p>
</div>
{/* 节点内容 */}
<div className="p-4 space-y-2">
<div className="nodrag">
<Label htmlFor={`chat-input-text-${id}`} className="text-xs font-semibold text-gray-500 dark:text-gray-400">Text</Label>
<Textarea
id={`chat-input-text-${id}`}
name="text"
value={data.text || ''}
onChange={handleTextChange}
placeholder="输入聊天内容..."
className="mt-1 text-sm min-h-[80px] bg-white dark:bg-gray-700"
rows={3}
/>
</div>
</div>
{/* 输出 Handle */}
<div className="relative p-2 border-t border-gray-300 dark:border-gray-600">
<Label className="text-xs font-semibold text-gray-500 dark:text-gray-400 block text-right pr-7">Message</Label>
<Handle
type="source"
position={Position.Right}
id="message-output"
isConnectable={isConnectable}
className="!w-3 !h-3 !bg-purple-500 top-1/2" // 使用紫色 Handle
/>
</div>
</div>
);
};
ChatInputNodeComponent.displayName = 'ChatInputNode';
export const ChatInputNode = memo(ChatInputNodeComponent);