// src/views/AgentChat/components/ChatArea/index.js // 中间聊天区域组件 import React from 'react'; import { motion, AnimatePresence } from 'framer-motion'; import { Box, Button, Input, Avatar, Badge, Tooltip, IconButton, Kbd, HStack, VStack, Flex, Text, Tag, TagLabel, TagCloseButton, } from '@chakra-ui/react'; import { Send, Menu, RefreshCw, Settings, Cpu, Zap, Sparkles, Paperclip, Image as ImageIcon, } from 'lucide-react'; import { AVAILABLE_MODELS } from '../../constants/models'; import { quickQuestions } from '../../constants/quickQuestions'; import { animations } from '../../constants/animations'; import MessageRenderer from './MessageRenderer'; /** * ChatArea - 中间聊天区域组件 * * @param {Object} props * @param {Array} props.messages - 消息列表 * @param {string} props.inputValue - 输入框内容 * @param {Function} props.onInputChange - 输入框变化回调 * @param {boolean} props.isProcessing - 处理中状态 * @param {Function} props.onSendMessage - 发送消息回调 * @param {Function} props.onKeyPress - 键盘事件回调 * @param {Array} props.uploadedFiles - 已上传文件列表 * @param {Function} props.onFileSelect - 文件选择回调 * @param {Function} props.onFileRemove - 文件删除回调 * @param {string} props.selectedModel - 当前选中的模型 ID * @param {boolean} props.isLeftSidebarOpen - 左侧栏是否展开 * @param {boolean} props.isRightSidebarOpen - 右侧栏是否展开 * @param {Function} props.onToggleLeftSidebar - 切换左侧栏回调 * @param {Function} props.onToggleRightSidebar - 切换右侧栏回调 * @param {Function} props.onNewSession - 新建会话回调 * @param {string} props.userAvatar - 用户头像 URL * @param {RefObject} props.messagesEndRef - 消息列表底部引用 * @param {RefObject} props.inputRef - 输入框引用 * @param {RefObject} props.fileInputRef - 文件上传输入引用 * @returns {JSX.Element} */ const ChatArea = ({ messages, inputValue, onInputChange, isProcessing, onSendMessage, onKeyPress, uploadedFiles, onFileSelect, onFileRemove, selectedModel, isLeftSidebarOpen, isRightSidebarOpen, onToggleLeftSidebar, onToggleRightSidebar, onNewSession, userAvatar, messagesEndRef, inputRef, fileInputRef, }) => { return ( {/* 顶部标题栏 - 深色毛玻璃 */} {!isLeftSidebarOpen && ( } onClick={onToggleLeftSidebar} bg="rgba(255, 255, 255, 0.05)" color="gray.400" backdropFilter="blur(10px)" border="1px solid" borderColor="rgba(255, 255, 255, 0.1)" _hover={{ bg: 'rgba(255, 255, 255, 0.1)', color: 'white', }} /> )} } bgGradient="linear(to-br, purple.500, pink.500)" boxShadow="0 0 20px rgba(236, 72, 153, 0.5)" /> 价小前投研 AI 智能分析 {AVAILABLE_MODELS.find((m) => m.id === selectedModel)?.name} } onClick={onNewSession} bg="rgba(255, 255, 255, 0.05)" color="gray.400" backdropFilter="blur(10px)" border="1px solid" borderColor="rgba(255, 255, 255, 0.1)" _hover={{ bg: 'rgba(255, 255, 255, 0.1)', color: 'white', borderColor: 'purple.400', boxShadow: '0 0 12px rgba(139, 92, 246, 0.3)', }} /> {!isRightSidebarOpen && ( } onClick={onToggleRightSidebar} bg="rgba(255, 255, 255, 0.05)" color="gray.400" backdropFilter="blur(10px)" border="1px solid" borderColor="rgba(255, 255, 255, 0.1)" _hover={{ bg: 'rgba(255, 255, 255, 0.1)', color: 'white', }} /> )} {/* 消息列表 */} {messages.map((message) => ( ))}
{/* 快捷问题 */} {messages.length <= 2 && !isProcessing && ( 快速开始 {quickQuestions.map((question, idx) => ( ))} )} {/* 输入栏 - 深色毛玻璃 */} {/* 已上传文件预览 */} {uploadedFiles.length > 0 && ( {uploadedFiles.map((file, idx) => ( {file.name} onFileRemove(idx)} color="gray.400" /> ))} )} } onClick={() => fileInputRef.current?.click()} bg="rgba(255, 255, 255, 0.05)" color="gray.300" backdropFilter="blur(10px)" border="1px solid" borderColor="rgba(255, 255, 255, 0.1)" _hover={{ bg: 'rgba(255, 255, 255, 0.1)', borderColor: 'purple.400', color: 'white', boxShadow: '0 0 12px rgba(139, 92, 246, 0.3)', }} /> } onClick={() => { fileInputRef.current?.setAttribute('accept', 'image/*'); fileInputRef.current?.click(); }} bg="rgba(255, 255, 255, 0.05)" color="gray.300" backdropFilter="blur(10px)" border="1px solid" borderColor="rgba(255, 255, 255, 0.1)" _hover={{ bg: 'rgba(255, 255, 255, 0.1)', borderColor: 'purple.400', color: 'white', boxShadow: '0 0 12px rgba(139, 92, 246, 0.3)', }} /> onInputChange(e.target.value)} onKeyDown={onKeyPress} placeholder="输入你的问题... (Enter 发送, Shift+Enter 换行)" isDisabled={isProcessing} size="lg" variant="outline" borderWidth={2} bg="rgba(255, 255, 255, 0.05)" backdropFilter="blur(10px)" border="1px solid" borderColor="rgba(255, 255, 255, 0.1)" color="white" _placeholder={{ color: 'gray.500' }} _hover={{ borderColor: 'rgba(255, 255, 255, 0.2)', }} _focus={{ borderColor: 'purple.400', boxShadow: '0 0 0 1px var(--chakra-colors-purple-400), 0 0 12px rgba(139, 92, 246, 0.3)', bg: 'rgba(255, 255, 255, 0.08)', }} /> } onClick={onSendMessage} isLoading={isProcessing} isDisabled={!inputValue.trim() || isProcessing} bgGradient="linear(to-r, blue.500, purple.600)" color="white" _hover={{ bgGradient: 'linear(to-r, blue.600, purple.700)', boxShadow: '0 8px 20px rgba(139, 92, 246, 0.4)', }} _active={{ transform: 'translateY(0)', boxShadow: '0 4px 12px rgba(139, 92, 246, 0.3)', }} /> Enter 发送 Shift + Enter 换行 ); }; export default ChatArea;