You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

195 lines
5.7 KiB
TypeScript

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

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;