Compare commits
3 Commits
5183473557
...
2d49af3bea
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
2d49af3bea | ||
|
|
3a0898634f | ||
|
|
44ecf7e5c7 |
@@ -30,12 +30,12 @@ const MemoizedAppFooter = memo(AppFooter);
|
||||
*/
|
||||
export default function MainLayout() {
|
||||
return (
|
||||
<Box minH="100vh" display="flex" flexDirection="column">
|
||||
<Box flex="1" h="100vh" w="100%" position="relative" display="flex" flexDirection="column">
|
||||
{/* 导航栏 - 在所有页面间共享,memo 后不会在路由切换时重新渲染 */}
|
||||
<MemoizedHomeNavbar />
|
||||
|
||||
{/* 页面内容区域 - flex: 1 占据剩余空间,包含错误边界、懒加载 */}
|
||||
<Box flex="1" w="100%" position="relative" overflow="hidden" pt="72px">
|
||||
<Box flex="1" pt="72px">
|
||||
<ErrorBoundary>
|
||||
<Suspense fallback={<PageLoader message="页面加载中..." />}>
|
||||
<Outlet />
|
||||
@@ -47,11 +47,11 @@ export default function MainLayout() {
|
||||
<MemoizedAppFooter />
|
||||
|
||||
{/* 返回顶部按钮 - 滚动超过阈值时显示 */}
|
||||
<BackToTopButton
|
||||
{/* <BackToTopButton
|
||||
scrollThreshold={BACK_TO_TOP_CONFIG.scrollThreshold}
|
||||
position={BACK_TO_TOP_CONFIG.position}
|
||||
zIndex={BACK_TO_TOP_CONFIG.zIndex}
|
||||
/>
|
||||
/> */}
|
||||
</Box>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1,59 +0,0 @@
|
||||
// src/views/AgentChat/components/BackgroundEffects.js
|
||||
// 背景渐变装饰层组件
|
||||
|
||||
import React from 'react';
|
||||
import { Box } from '@chakra-ui/react';
|
||||
|
||||
/**
|
||||
* BackgroundEffects - 背景渐变装饰层
|
||||
*
|
||||
* 包含主背景渐变和两个装饰光效(右上紫色、左下蓝色)
|
||||
*
|
||||
* @returns {JSX.Element}
|
||||
*/
|
||||
const BackgroundEffects = () => {
|
||||
return (
|
||||
<>
|
||||
{/* 主背景渐变层 */}
|
||||
<Box
|
||||
position="absolute"
|
||||
top={0}
|
||||
left={0}
|
||||
right={0}
|
||||
bottom={0}
|
||||
bgGradient="linear(to-br, gray.900, gray.800, purple.900)"
|
||||
zIndex={0}
|
||||
/>
|
||||
|
||||
{/* 右上角紫色光效 */}
|
||||
<Box
|
||||
position="absolute"
|
||||
top="0"
|
||||
right="-20%"
|
||||
width="600px"
|
||||
height="600px"
|
||||
bgGradient="radial(circle, purple.600, transparent)"
|
||||
opacity="0.15"
|
||||
filter="blur(100px)"
|
||||
pointerEvents="none"
|
||||
zIndex={0}
|
||||
/>
|
||||
|
||||
{/* 左下角蓝色光效 */}
|
||||
<Box
|
||||
position="absolute"
|
||||
bottom="-30%"
|
||||
left="-10%"
|
||||
width="500px"
|
||||
height="500px"
|
||||
bgGradient="radial(circle, blue.600, transparent)"
|
||||
opacity="0.1"
|
||||
filter="blur(100px)"
|
||||
pointerEvents="none"
|
||||
zIndex={0}
|
||||
/>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export default BackgroundEffects;
|
||||
@@ -1,7 +1,7 @@
|
||||
// src/views/AgentChat/components/ChatArea/index.js
|
||||
// 中间聊天区域组件
|
||||
|
||||
import React from 'react';
|
||||
import React, { useRef, useEffect } from 'react';
|
||||
import { motion, AnimatePresence } from 'framer-motion';
|
||||
import {
|
||||
Box,
|
||||
@@ -56,7 +56,6 @@ import MessageRenderer from './MessageRenderer';
|
||||
* @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}
|
||||
@@ -78,10 +77,15 @@ const ChatArea = ({
|
||||
onToggleRightSidebar,
|
||||
onNewSession,
|
||||
userAvatar,
|
||||
messagesEndRef,
|
||||
inputRef,
|
||||
fileInputRef,
|
||||
}) => {
|
||||
// Auto-scroll 功能:当消息列表更新时,自动滚动到底部
|
||||
const messagesEndRef = useRef(null);
|
||||
|
||||
useEffect(() => {
|
||||
messagesEndRef.current?.scrollIntoView({ behavior: 'smooth' });
|
||||
}, [messages]);
|
||||
return (
|
||||
<Flex flex={1} direction="column">
|
||||
{/* 顶部标题栏 - 深色毛玻璃 */}
|
||||
@@ -214,7 +218,6 @@ const ChatArea = ({
|
||||
{/* 消息列表 */}
|
||||
<Box
|
||||
flex={1}
|
||||
p={6}
|
||||
bgGradient="linear(to-b, rgba(17, 24, 39, 0.5), rgba(17, 24, 39, 0.3))"
|
||||
overflowY="auto"
|
||||
>
|
||||
@@ -253,7 +256,7 @@ const ChatArea = ({
|
||||
animate="animate"
|
||||
exit={{ opacity: 0, y: 20 }}
|
||||
>
|
||||
<Box px={6} py={3}>
|
||||
<Box px={6}>
|
||||
<Box maxW="896px" mx="auto">
|
||||
<HStack fontSize="xs" color="gray.500" mb={2} fontWeight="medium" spacing={1}>
|
||||
<Sparkles className="w-3 h-3" />
|
||||
@@ -308,7 +311,7 @@ const ChatArea = ({
|
||||
borderTop="1px solid"
|
||||
borderColor="rgba(255, 255, 255, 0.1)"
|
||||
px={6}
|
||||
py={4}
|
||||
py={1}
|
||||
boxShadow="0 -8px 32px 0 rgba(31, 38, 135, 0.37)"
|
||||
>
|
||||
<Box maxW="896px" mx="auto">
|
||||
|
||||
@@ -71,6 +71,7 @@ const LeftSidebar = ({
|
||||
>
|
||||
<Box
|
||||
w="320px"
|
||||
h="100%"
|
||||
display="flex"
|
||||
flexDirection="column"
|
||||
bg="rgba(17, 24, 39, 0.8)"
|
||||
|
||||
@@ -78,6 +78,7 @@ const RightSidebar = ({
|
||||
>
|
||||
<Box
|
||||
w="320px"
|
||||
h="100%"
|
||||
display="flex"
|
||||
flexDirection="column"
|
||||
bg="rgba(17, 24, 39, 0.8)"
|
||||
|
||||
@@ -2,8 +2,8 @@
|
||||
// 超炫酷的 AI 投研助手 - HeroUI v3 现代深色主题版本
|
||||
// 使用 Framer Motion 物理动画引擎 + 毛玻璃效果
|
||||
|
||||
import React, { useState, useEffect } from 'react';
|
||||
import { Box, Flex, useToast, useColorMode } from '@chakra-ui/react';
|
||||
import React, { useState } from 'react';
|
||||
import { Box, Flex, useToast } from '@chakra-ui/react';
|
||||
import { useAuth } from '@contexts/AuthContext';
|
||||
|
||||
// 常量配置 - 从 TypeScript 模块导入
|
||||
@@ -11,13 +11,12 @@ import { DEFAULT_MODEL_ID } from './constants/models';
|
||||
import { DEFAULT_SELECTED_TOOLS } from './constants/tools';
|
||||
|
||||
// 拆分后的子组件
|
||||
import BackgroundEffects from './components/BackgroundEffects';
|
||||
import LeftSidebar from './components/LeftSidebar';
|
||||
import ChatArea from './components/ChatArea';
|
||||
import RightSidebar from './components/RightSidebar';
|
||||
|
||||
// 自定义 Hooks
|
||||
import { useAgentSessions, useAgentChat, useFileUpload, useAutoScroll } from './hooks';
|
||||
import { useAgentSessions, useAgentChat, useFileUpload } from './hooks';
|
||||
|
||||
/**
|
||||
* Agent Chat - 主组件(HeroUI v3 深色主题)
|
||||
@@ -35,7 +34,6 @@ import { useAgentSessions, useAgentChat, useFileUpload, useAutoScroll } from './
|
||||
const AgentChat = () => {
|
||||
const { user } = useAuth();
|
||||
const toast = useToast();
|
||||
const { setColorMode } = useColorMode();
|
||||
|
||||
// ==================== UI 状态(主组件管理)====================
|
||||
const [selectedModel, setSelectedModel] = useState(DEFAULT_MODEL_ID);
|
||||
@@ -83,79 +81,58 @@ const AgentChat = () => {
|
||||
loadSessions,
|
||||
});
|
||||
|
||||
// 自动滚动 Hook
|
||||
const { messagesEndRef } = useAutoScroll(messages);
|
||||
|
||||
// ==================== 输入框引用(保留在主组件)====================
|
||||
const inputRef = React.useRef(null);
|
||||
|
||||
// ==================== 启用深色模式 ====================
|
||||
useEffect(() => {
|
||||
// 为 AgentChat 页面强制启用深色模式
|
||||
setColorMode('dark');
|
||||
document.documentElement.classList.add('dark');
|
||||
|
||||
return () => {
|
||||
// 组件卸载时不移除,让其他页面自己控制
|
||||
// document.documentElement.classList.remove('dark');
|
||||
};
|
||||
}, [setColorMode]);
|
||||
|
||||
// ==================== 渲染组件 ====================
|
||||
return (
|
||||
<Box flex={1} bg="gray.900">
|
||||
<Flex h="100%" overflow="hidden" position="relative">
|
||||
{/* 背景渐变装饰 */}
|
||||
<BackgroundEffects />
|
||||
<Flex h="100%" position="relative" bg="gray.900">
|
||||
{/* 左侧栏 */}
|
||||
<LeftSidebar
|
||||
isOpen={isLeftSidebarOpen}
|
||||
onClose={() => setIsLeftSidebarOpen(false)}
|
||||
sessions={sessions}
|
||||
currentSessionId={currentSessionId}
|
||||
onSessionSwitch={switchSession}
|
||||
onNewSession={createNewSession}
|
||||
isLoadingSessions={isLoadingSessions}
|
||||
user={user}
|
||||
/>
|
||||
|
||||
{/* 左侧栏 */}
|
||||
<LeftSidebar
|
||||
isOpen={isLeftSidebarOpen}
|
||||
onClose={() => setIsLeftSidebarOpen(false)}
|
||||
sessions={sessions}
|
||||
currentSessionId={currentSessionId}
|
||||
onSessionSwitch={switchSession}
|
||||
onNewSession={createNewSession}
|
||||
isLoadingSessions={isLoadingSessions}
|
||||
user={user}
|
||||
/>
|
||||
{/* 中间聊天区 */}
|
||||
<ChatArea
|
||||
messages={messages}
|
||||
inputValue={inputValue}
|
||||
onInputChange={setInputValue}
|
||||
isProcessing={isProcessing}
|
||||
onSendMessage={handleSendMessage}
|
||||
onKeyPress={handleKeyPress}
|
||||
uploadedFiles={uploadedFiles}
|
||||
onFileSelect={handleFileSelect}
|
||||
onFileRemove={removeFile}
|
||||
selectedModel={selectedModel}
|
||||
isLeftSidebarOpen={isLeftSidebarOpen}
|
||||
isRightSidebarOpen={isRightSidebarOpen}
|
||||
onToggleLeftSidebar={() => setIsLeftSidebarOpen(true)}
|
||||
onToggleRightSidebar={() => setIsRightSidebarOpen(true)}
|
||||
onNewSession={createNewSession}
|
||||
userAvatar={user?.avatar}
|
||||
inputRef={inputRef}
|
||||
fileInputRef={fileInputRef}
|
||||
/>
|
||||
|
||||
{/* 中间聊天区 */}
|
||||
<ChatArea
|
||||
messages={messages}
|
||||
inputValue={inputValue}
|
||||
onInputChange={setInputValue}
|
||||
isProcessing={isProcessing}
|
||||
onSendMessage={handleSendMessage}
|
||||
onKeyPress={handleKeyPress}
|
||||
uploadedFiles={uploadedFiles}
|
||||
onFileSelect={handleFileSelect}
|
||||
onFileRemove={removeFile}
|
||||
selectedModel={selectedModel}
|
||||
isLeftSidebarOpen={isLeftSidebarOpen}
|
||||
isRightSidebarOpen={isRightSidebarOpen}
|
||||
onToggleLeftSidebar={() => setIsLeftSidebarOpen(true)}
|
||||
onToggleRightSidebar={() => setIsRightSidebarOpen(true)}
|
||||
onNewSession={createNewSession}
|
||||
userAvatar={user?.avatar}
|
||||
messagesEndRef={messagesEndRef}
|
||||
inputRef={inputRef}
|
||||
fileInputRef={fileInputRef}
|
||||
/>
|
||||
|
||||
{/* 右侧栏 */}
|
||||
<RightSidebar
|
||||
isOpen={isRightSidebarOpen}
|
||||
onClose={() => setIsRightSidebarOpen(false)}
|
||||
selectedModel={selectedModel}
|
||||
onModelChange={setSelectedModel}
|
||||
selectedTools={selectedTools}
|
||||
onToolsChange={setSelectedTools}
|
||||
sessionsCount={sessions.length}
|
||||
messagesCount={messages.length}
|
||||
/>
|
||||
</Flex>
|
||||
</Box>
|
||||
{/* 右侧栏 */}
|
||||
<RightSidebar
|
||||
isOpen={isRightSidebarOpen}
|
||||
onClose={() => setIsRightSidebarOpen(false)}
|
||||
selectedModel={selectedModel}
|
||||
onModelChange={setSelectedModel}
|
||||
selectedTools={selectedTools}
|
||||
onToolsChange={setSelectedTools}
|
||||
sessionsCount={sessions.length}
|
||||
messagesCount={messages.length}
|
||||
/>
|
||||
</Flex>
|
||||
);
|
||||
};
|
||||
|
||||
|
||||
Reference in New Issue
Block a user