Files
AIclinicalresearch/frontend/src/components/chat/MessageInput.tsx
AI Clinical Dev Team be56c3d35d fix: dropdown click issue
2025-10-11 18:05:28 +08:00

184 lines
5.1 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import React, { useState, useRef, KeyboardEvent } from 'react';
import { Input, Button, Space, Tooltip, Dropdown, Tag } from 'antd';
import {
SendOutlined,
PaperClipOutlined,
FileTextOutlined,
CloseCircleOutlined
} from '@ant-design/icons';
import type { MenuProps } from 'antd';
import './MessageInput.css';
const { TextArea } = Input;
interface KnowledgeBase {
id: string;
name: string;
}
interface MessageInputProps {
onSend: (content: string, knowledgeBaseIds: string[]) => void;
loading?: boolean;
knowledgeBases?: KnowledgeBase[];
placeholder?: string;
}
const MessageInput: React.FC<MessageInputProps> = ({
onSend,
loading = false,
knowledgeBases = [],
placeholder = '输入你的问题...Shift+Enter换行Enter发送',
}) => {
const [content, setContent] = useState('');
const [selectedKnowledgeBases, setSelectedKnowledgeBases] = useState<string[]>([]);
const textAreaRef = useRef<any>(null);
// 处理发送消息
const handleSend = () => {
const trimmedContent = content.trim();
if (!trimmedContent || loading) return;
onSend(trimmedContent, selectedKnowledgeBases);
setContent('');
setSelectedKnowledgeBases([]);
// 重置输入框高度
if (textAreaRef.current) {
textAreaRef.current.resizableTextArea.textArea.style.height = 'auto';
}
};
// 处理键盘事件
const handleKeyDown = (e: KeyboardEvent<HTMLTextAreaElement>) => {
// Enter发送Shift+Enter换行
if (e.key === 'Enter' && !e.shiftKey) {
e.preventDefault();
handleSend();
}
};
// 添加知识库
const handleSelectKnowledgeBase = (kbId: string) => {
if (!selectedKnowledgeBases.includes(kbId)) {
setSelectedKnowledgeBases([...selectedKnowledgeBases, kbId]);
}
};
// 移除知识库
const handleRemoveKnowledgeBase = (kbId: string) => {
setSelectedKnowledgeBases(selectedKnowledgeBases.filter(id => id !== kbId));
};
// 知识库下拉菜单
const knowledgeBaseMenuItems: MenuProps['items'] = knowledgeBases.map(kb => ({
key: kb.id,
label: kb.name,
icon: <FileTextOutlined />,
onClick: () => handleSelectKnowledgeBase(kb.id),
disabled: selectedKnowledgeBases.includes(kb.id),
}));
// 获取选中的知识库名称
const getKnowledgeBaseName = (kbId: string) => {
const kb = knowledgeBases.find(k => k.id === kbId);
return kb ? kb.name : kbId;
};
return (
<div className="message-input-container">
{/* 已选择的知识库标签 */}
{selectedKnowledgeBases.length > 0 && (
<div className="selected-knowledge-bases">
<Space wrap>
{selectedKnowledgeBases.map(kbId => (
<Tag
key={kbId}
closable
color="blue"
onClose={() => handleRemoveKnowledgeBase(kbId)}
closeIcon={<CloseCircleOutlined />}
>
<FileTextOutlined /> {getKnowledgeBaseName(kbId)}
</Tag>
))}
</Space>
</div>
)}
{/* 输入框和工具栏 */}
<div className="message-input-wrapper">
<TextArea
ref={textAreaRef}
value={content}
onChange={(e) => setContent(e.target.value)}
onKeyDown={handleKeyDown}
placeholder={placeholder}
autoSize={{ minRows: 2, maxRows: 8 }}
disabled={loading}
className="message-textarea"
/>
<div className="message-input-toolbar">
<Space>
{/* @知识库按钮 */}
{knowledgeBases.length > 0 && (
<Tooltip title="@知识库 - 基于知识库内容回答">
<Dropdown
menu={{ items: knowledgeBaseMenuItems }}
placement="topLeft"
trigger={['click']}
disabled={loading}
>
<Button
icon={<FileTextOutlined />}
type="text"
disabled={loading}
>
@知识库
</Button>
</Dropdown>
</Tooltip>
)}
{/* 上传附件按钮(预留) */}
<Tooltip title="上传文档(即将上线)">
<Button
icon={<PaperClipOutlined />}
type="text"
disabled
/>
</Tooltip>
</Space>
{/* 发送按钮 */}
<Button
type="primary"
icon={<SendOutlined />}
onClick={handleSend}
loading={loading}
disabled={!content.trim() || loading}
>
</Button>
</div>
</div>
{/* 提示信息 */}
<div className="message-input-hint">
<span>Shift + Enter Enter </span>
{selectedKnowledgeBases.length > 0 && (
<span className="kb-hint">
· {selectedKnowledgeBases.length}
</span>
)}
</div>
</div>
);
};
export default MessageInput;