184 lines
5.1 KiB
TypeScript
184 lines
5.1 KiB
TypeScript
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;
|
||
|
||
|
||
|
||
|