|
|
import React, { useState, useRef, useEffect } from 'react';
|
|
|
import { Avatar, Input, Button, List, Typography, Tabs } from '@arco-design/web-react';
|
|
|
import { IconSend, IconRobot, IconUser } from '@arco-design/web-react/icon';
|
|
|
import styles from './style/chatBox.module.less';
|
|
|
|
|
|
const { TextArea } = Input;
|
|
|
const TabPane = Tabs.TabPane;
|
|
|
|
|
|
interface Message {
|
|
|
id: string;
|
|
|
content: string;
|
|
|
role: 'user' | 'assistant';
|
|
|
timestamp: Date;
|
|
|
}
|
|
|
|
|
|
const ChatBox: React.FC = () => {
|
|
|
const [activeTab, setActiveTab] = useState('1');
|
|
|
const [messages, setMessages] = useState<Message[]>([
|
|
|
{
|
|
|
id: '1',
|
|
|
content: '你好!我是AI助手,有什么我可以帮助你的吗?',
|
|
|
role: 'assistant',
|
|
|
timestamp: new Date()
|
|
|
}
|
|
|
]);
|
|
|
const [inputValue, setInputValue] = useState('');
|
|
|
const [loading, setLoading] = useState(false);
|
|
|
const messagesEndRef = useRef<HTMLDivElement>(null);
|
|
|
|
|
|
// 滚动到最新消息
|
|
|
const scrollToBottom = () => {
|
|
|
messagesEndRef.current?.scrollIntoView({ behavior: 'smooth' });
|
|
|
};
|
|
|
|
|
|
useEffect(() => {
|
|
|
scrollToBottom();
|
|
|
}, [messages]);
|
|
|
|
|
|
// 发送消息
|
|
|
const handleSend = async () => {
|
|
|
if (!inputValue.trim() || loading) return;
|
|
|
|
|
|
// 添加用户消息
|
|
|
const userMessage: Message = {
|
|
|
id: Date.now().toString(),
|
|
|
content: inputValue,
|
|
|
role: 'user',
|
|
|
timestamp: new Date()
|
|
|
};
|
|
|
|
|
|
setMessages(prev => [...prev, userMessage]);
|
|
|
setInputValue('');
|
|
|
setLoading(true);
|
|
|
|
|
|
try {
|
|
|
// 模拟AI回复(实际项目中这里会调用API)
|
|
|
setTimeout(() => {
|
|
|
let response = '';
|
|
|
switch (activeTab) {
|
|
|
case '1':
|
|
|
response = `关于应用编排,我收到你的消息:"${inputValue}"。应用编排可以帮助你设计和管理复杂的应用流程。`;
|
|
|
break;
|
|
|
case '2':
|
|
|
response = `关于组件编排,我收到你的消息:"${inputValue}"。组件编排可以让你灵活组合和配置各种功能组件。`;
|
|
|
break;
|
|
|
case '3':
|
|
|
response = `关于组件推荐,我收到你的消息:"${inputValue}"。基于你的需求,我推荐以下组件:1.数据表格组件 2.图表组件 3.表单组件。`;
|
|
|
break;
|
|
|
default:
|
|
|
response = `我收到了你的消息:"${inputValue}"。这是一个模拟回复,实际项目中这里会接入AI接口。`;
|
|
|
}
|
|
|
|
|
|
const aiMessage: Message = {
|
|
|
id: (Date.now() + 1).toString(),
|
|
|
content: response,
|
|
|
role: 'assistant',
|
|
|
timestamp: new Date()
|
|
|
};
|
|
|
setMessages(prev => [...prev, aiMessage]);
|
|
|
setLoading(false);
|
|
|
}, 1000);
|
|
|
} catch (error) {
|
|
|
const errorMessage: Message = {
|
|
|
id: (Date.now() + 1).toString(),
|
|
|
content: '抱歉,我遇到了一些问题,请稍后再试。',
|
|
|
role: 'assistant',
|
|
|
timestamp: new Date()
|
|
|
};
|
|
|
setMessages(prev => [...prev, errorMessage]);
|
|
|
setLoading(false);
|
|
|
}
|
|
|
};
|
|
|
|
|
|
// 处理回车发送
|
|
|
const handleKeyPress = (e: React.KeyboardEvent<HTMLTextAreaElement>) => {
|
|
|
if (e.key === 'Enter' && !e.shiftKey) {
|
|
|
e.preventDefault();
|
|
|
handleSend();
|
|
|
}
|
|
|
};
|
|
|
|
|
|
// 格式化时间
|
|
|
const formatTime = (date: Date) => {
|
|
|
return date.toLocaleTimeString([], { hour: '2-digit', minute: '2-digit' });
|
|
|
};
|
|
|
|
|
|
return (
|
|
|
<div className={styles['chat-container']}>
|
|
|
<div className={styles['chat-header']}>
|
|
|
<Tabs
|
|
|
activeTab={activeTab}
|
|
|
onChange={setActiveTab}
|
|
|
type="rounded"
|
|
|
size="small"
|
|
|
>
|
|
|
<TabPane
|
|
|
key="1"
|
|
|
title={
|
|
|
<span>
|
|
|
应用编排
|
|
|
</span>
|
|
|
}
|
|
|
/>
|
|
|
<TabPane
|
|
|
key="2"
|
|
|
title={
|
|
|
<span>
|
|
|
组件编排
|
|
|
</span>
|
|
|
}
|
|
|
/>
|
|
|
<TabPane
|
|
|
key="3"
|
|
|
title={
|
|
|
<span>
|
|
|
组件推荐
|
|
|
</span>
|
|
|
}
|
|
|
/>
|
|
|
</Tabs>
|
|
|
</div>
|
|
|
|
|
|
<div className={styles['chat-messages']}>
|
|
|
<List
|
|
|
dataSource={messages}
|
|
|
render={(item) => (
|
|
|
<List.Item key={item.id} className={styles['message-item']}>
|
|
|
<div className={`${styles['message-content']} ${styles[item.role]}`}>
|
|
|
<div className={styles['message-avatar']}>
|
|
|
<Avatar size={28} style={{
|
|
|
backgroundColor: item.role === 'user' ? '#165dff' : '#626aea'
|
|
|
}}>
|
|
|
{item.role === 'user' ? <IconUser /> : <IconRobot />}
|
|
|
</Avatar>
|
|
|
</div>
|
|
|
<div className={styles['message-main']}>
|
|
|
<div className={styles['message-text']}>
|
|
|
{item.content}
|
|
|
</div>
|
|
|
<div className={styles['message-time']}>
|
|
|
{formatTime(item.timestamp)}
|
|
|
</div>
|
|
|
</div>
|
|
|
</div>
|
|
|
</List.Item>
|
|
|
)}
|
|
|
/>
|
|
|
<div ref={messagesEndRef} />
|
|
|
</div>
|
|
|
|
|
|
<div className={styles['chat-input']}>
|
|
|
<TextArea
|
|
|
value={inputValue}
|
|
|
onChange={setInputValue}
|
|
|
onPressEnter={handleKeyPress}
|
|
|
placeholder={`在${['应用编排', '组件编排', '组件推荐'][Number(activeTab) - 1]}中输入消息...`}
|
|
|
autoSize={{ minRows: 2, maxRows: 4 }}
|
|
|
disabled={loading}
|
|
|
/>
|
|
|
<Button
|
|
|
type="primary"
|
|
|
icon={<IconSend />}
|
|
|
onClick={handleSend}
|
|
|
loading={loading}
|
|
|
style={{ marginTop: 10 }}
|
|
|
>
|
|
|
发送
|
|
|
</Button>
|
|
|
</div>
|
|
|
</div>
|
|
|
);
|
|
|
};
|
|
|
|
|
|
export default ChatBox;
|