From d37c974d234fd14e60a7621ce65aafbf9f80dfa3 Mon Sep 17 00:00:00 2001 From: zdl <3489966805@qq.com> Date: Tue, 25 Nov 2025 15:53:12 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E7=BB=84=E7=BB=84=E4=BB=B6=E6=8B=86?= =?UTF-8?q?=E5=88=86?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../components/RightSidebar/ModelSelector.tsx | 118 +++++ .../components/RightSidebar/Statistics.tsx | 119 +++++ .../components/RightSidebar/ToolSelector.tsx | 199 +++++++ .../components/RightSidebar/index.js | 499 ------------------ .../components/RightSidebar/index.tsx | 240 +++++++++ .../components/RightSidebar/types.ts | 27 + 6 files changed, 703 insertions(+), 499 deletions(-) create mode 100644 src/views/AgentChat/components/RightSidebar/ModelSelector.tsx create mode 100644 src/views/AgentChat/components/RightSidebar/Statistics.tsx create mode 100644 src/views/AgentChat/components/RightSidebar/ToolSelector.tsx delete mode 100644 src/views/AgentChat/components/RightSidebar/index.js create mode 100644 src/views/AgentChat/components/RightSidebar/index.tsx create mode 100644 src/views/AgentChat/components/RightSidebar/types.ts diff --git a/src/views/AgentChat/components/RightSidebar/ModelSelector.tsx b/src/views/AgentChat/components/RightSidebar/ModelSelector.tsx new file mode 100644 index 00000000..dcbc4b49 --- /dev/null +++ b/src/views/AgentChat/components/RightSidebar/ModelSelector.tsx @@ -0,0 +1,118 @@ +// src/views/AgentChat/components/RightSidebar/ModelSelector.tsx +// 模型选择组件 + +import React from 'react'; +import { motion } from 'framer-motion'; +import { + Card, + CardBody, + HStack, + VStack, + Box, + Text, +} from '@chakra-ui/react'; +import { Check } from 'lucide-react'; +import { AVAILABLE_MODELS } from '../../constants/models'; + +/** + * ModelSelector 组件的 Props 类型 + */ +interface ModelSelectorProps { + /** 当前选中的模型 ID */ + selectedModel: string; + /** 模型切换回调 */ + onModelChange: (modelId: string) => void; +} + +/** + * ModelSelector - 模型选择组件 + * + * 职责: + * 1. 渲染模型选择卡片列表 + * 2. 显示模型图标、名称、描述 + * 3. 高亮当前选中模型(紫色边框 + 发光效果) + * 4. 显示选中标记(Check 图标 + 弹簧动画) + * + * 设计特性: + * - 卡片渐进入场动画(延迟 `idx * 0.1`) + * - 悬停缩放 1.02x + 上移 2px + * - 选中态:紫色边框 + 发光效果 + * - 模型图标渐变色背景 + */ +const ModelSelector: React.FC = ({ selectedModel, onModelChange }) => { + return ( + + {AVAILABLE_MODELS.map((model, idx) => { + const isSelected = selectedModel === model.id; + + return ( + + onModelChange(model.id)} + bg={isSelected ? 'rgba(139, 92, 246, 0.15)' : 'rgba(255, 255, 255, 0.05)'} + backdropFilter="blur(12px)" + borderWidth={2} + borderColor={isSelected ? 'purple.400' : 'rgba(255, 255, 255, 0.1)'} + _hover={{ + borderColor: isSelected ? 'purple.400' : 'rgba(255, 255, 255, 0.2)', + boxShadow: isSelected + ? '0 8px 20px rgba(139, 92, 246, 0.4)' + : '0 4px 12px rgba(0, 0, 0, 0.3)', + }} + transition="all 0.3s" + > + + + {/* 模型图标 */} + + {model.icon} + + + {/* 模型信息 */} + + + {model.name} + + + {model.description} + + + + {/* 选中标记(Check 图标) */} + {isSelected && ( + + + + )} + + + + + ); + })} + + ); +}; + +export default ModelSelector; diff --git a/src/views/AgentChat/components/RightSidebar/Statistics.tsx b/src/views/AgentChat/components/RightSidebar/Statistics.tsx new file mode 100644 index 00000000..af416d32 --- /dev/null +++ b/src/views/AgentChat/components/RightSidebar/Statistics.tsx @@ -0,0 +1,119 @@ +// src/views/AgentChat/components/RightSidebar/Statistics.tsx +// 统计信息组件 + +import React from 'react'; +import { motion } from 'framer-motion'; +import { + Card, + CardBody, + VStack, + Flex, + Box, + Text, +} from '@chakra-ui/react'; +import { MessageSquare, Activity, Code } from 'lucide-react'; + +/** + * Statistics 组件的 Props 类型 + */ +interface StatisticsProps { + /** 对话总数 */ + sessionsCount: number; + /** 消息总数 */ + messagesCount: number; + /** 已选工具数 */ + selectedToolsCount: number; +} + +/** + * Statistics - 统计信息组件 + * + * 职责: + * 1. 显示统计卡片(对话数、消息数、已选工具数) + * 2. 渐变色大数字展示 + * 3. 图标装饰 + * + * 设计特性: + * - 卡片渐进入场动画(延迟 `idx * 0.1`) + * - 毛玻璃效果卡片 + * - 渐变色数字(蓝紫/紫粉/绿青) + * - 半透明图标装饰 + */ +const Statistics: React.FC = ({ + sessionsCount, + messagesCount, + selectedToolsCount, +}) => { + const stats = [ + { + label: '对话数', + value: sessionsCount, + gradient: 'linear(to-r, blue.400, purple.400)', + icon: MessageSquare, + iconColor: '#60A5FA', + }, + { + label: '消息数', + value: messagesCount, + gradient: 'linear(to-r, purple.400, pink.400)', + icon: Activity, + iconColor: '#C084FC', + }, + { + label: '已选工具', + value: selectedToolsCount, + gradient: 'linear(to-r, green.400, teal.400)', + icon: Code, + iconColor: '#34D399', + }, + ]; + + return ( + + {stats.map((stat, idx) => { + const Icon = stat.icon; + + return ( + + + + + {/* 左侧:标签和数值 */} + + + {stat.label} + + + {stat.value} + + + + {/* 右侧:图标装饰 */} + + + + + + ); + })} + + ); +}; + +export default Statistics; diff --git a/src/views/AgentChat/components/RightSidebar/ToolSelector.tsx b/src/views/AgentChat/components/RightSidebar/ToolSelector.tsx new file mode 100644 index 00000000..a83756cd --- /dev/null +++ b/src/views/AgentChat/components/RightSidebar/ToolSelector.tsx @@ -0,0 +1,199 @@ +// src/views/AgentChat/components/RightSidebar/ToolSelector.tsx +// 工具选择组件 + +import React from 'react'; +import { motion } from 'framer-motion'; +import { + Button, + Badge, + Checkbox, + CheckboxGroup, + Accordion, + AccordionItem, + AccordionButton, + AccordionPanel, + AccordionIcon, + HStack, + VStack, + Box, + Text, +} from '@chakra-ui/react'; +import { MCP_TOOLS, TOOL_CATEGORIES } from '../../constants/tools'; + +/** + * ToolSelector 组件的 Props 类型 + */ +interface ToolSelectorProps { + /** 已选工具 ID 列表 */ + selectedTools: string[]; + /** 工具选择变化回调 */ + onToolsChange: (tools: string[]) => void; +} + +/** + * ToolSelector - 工具选择组件 + * + * 职责: + * 1. 按分类展示工具列表(Accordion 手风琴) + * 2. 复选框选择/取消工具 + * 3. 显示每个分类的已选/总数(如 "3/5") + * 4. 全选/清空按钮 + * + * 设计特性: + * - 手风琴分类折叠 + * - 悬停工具项右移 4px + * - 全选/清空按钮渐变色 + * - 分类徽章显示选中数量 + */ +const ToolSelector: React.FC = ({ selectedTools, onToolsChange }) => { + /** + * 全选所有工具 + */ + const handleSelectAll = () => { + onToolsChange(MCP_TOOLS.map((t) => t.id)); + }; + + /** + * 清空所有选择 + */ + const handleClearAll = () => { + onToolsChange([]); + }; + + return ( + <> + {/* 工具分类手风琴 */} + + {Object.entries(TOOL_CATEGORIES).map(([category, tools], catIdx) => { + const selectedCount = tools.filter((t) => selectedTools.includes(t.id)).length; + const totalCount = tools.length; + + return ( + + + {/* 手风琴标题 */} + + + + {category} + + + {selectedCount}/{totalCount} + + + + + + {/* 手风琴内容 */} + + + + {tools.map((tool) => ( + + + + {/* 工具图标 */} + + {tool.icon} + + + {/* 工具信息 */} + + + {tool.name} + + + {tool.description} + + + + + + ))} + + + + + + ); + })} + + + {/* 全选/清空按钮 */} + + {/* 全选按钮 */} + + + + + {/* 清空按钮 */} + + + + + + ); +}; + +export default ToolSelector; diff --git a/src/views/AgentChat/components/RightSidebar/index.js b/src/views/AgentChat/components/RightSidebar/index.js deleted file mode 100644 index 0760af0a..00000000 --- a/src/views/AgentChat/components/RightSidebar/index.js +++ /dev/null @@ -1,499 +0,0 @@ -// src/views/AgentChat/components/RightSidebar/index.js -// 右侧栏组件 - 配置中心 - -import React from 'react'; -import { motion, AnimatePresence } from 'framer-motion'; -import { - Box, - Button, - Badge, - Checkbox, - CheckboxGroup, - Tooltip, - IconButton, - Accordion, - AccordionItem, - AccordionButton, - AccordionPanel, - AccordionIcon, - Tabs, - TabList, - TabPanels, - Tab, - TabPanel, - Card, - CardBody, - HStack, - VStack, - Flex, - Text, -} from '@chakra-ui/react'; -import { - Settings, - ChevronRight, - Cpu, - Code, - BarChart3, - Check, - MessageSquare, - Activity, -} from 'lucide-react'; -import { animations } from '../../constants/animations'; -import { AVAILABLE_MODELS } from '../../constants/models'; -import { MCP_TOOLS, TOOL_CATEGORIES } from '../../constants/tools'; - -/** - * RightSidebar - 右侧栏组件(配置中心) - * - * @param {Object} props - * @param {boolean} props.isOpen - 侧边栏是否展开 - * @param {Function} props.onClose - 关闭侧边栏回调 - * @param {string} props.selectedModel - 当前选中的模型 ID - * @param {Function} props.onModelChange - 模型切换回调 - * @param {Array} props.selectedTools - 已选工具 ID 列表 - * @param {Function} props.onToolsChange - 工具选择变化回调 - * @param {number} props.sessionsCount - 会话总数 - * @param {number} props.messagesCount - 消息总数 - * @returns {JSX.Element|null} - */ -const RightSidebar = ({ - isOpen, - onClose, - selectedModel, - onModelChange, - selectedTools, - onToolsChange, - sessionsCount, - messagesCount, -}) => { - return ( - - {isOpen && ( - - - {/* 标题栏 */} - - - - - - 配置中心 - - - - - } - onClick={onClose} - 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', - }} - /> - - - - - - {/* Tab 面板 */} - - - - - - - 模型 - - - - - - 工具 - {selectedTools.length > 0 && ( - - {selectedTools.length} - - )} - - - - - - 统计 - - - - - - {/* 模型选择 */} - - - {AVAILABLE_MODELS.map((model, idx) => ( - - onModelChange(model.id)} - bg={ - selectedModel === model.id - ? 'rgba(139, 92, 246, 0.15)' - : 'rgba(255, 255, 255, 0.05)' - } - backdropFilter="blur(12px)" - borderWidth={2} - borderColor={ - selectedModel === model.id ? 'purple.400' : 'rgba(255, 255, 255, 0.1)' - } - _hover={{ - borderColor: - selectedModel === model.id ? 'purple.400' : 'rgba(255, 255, 255, 0.2)', - boxShadow: - selectedModel === model.id - ? '0 8px 20px rgba(139, 92, 246, 0.4)' - : '0 4px 12px rgba(0, 0, 0, 0.3)', - }} - transition="all 0.3s" - > - - - - {model.icon} - - - - {model.name} - - - {model.description} - - - {selectedModel === model.id && ( - - - - )} - - - - - ))} - - - - {/* 工具选择 */} - - - {Object.entries(TOOL_CATEGORIES).map(([category, tools], catIdx) => ( - - - - - - {category} - - - {tools.filter((t) => selectedTools.includes(t.id)).length}/{tools.length} - - - - - - - - {tools.map((tool) => ( - - - - - {tool.icon} - - - - {tool.name} - - - {tool.description} - - - - - - ))} - - - - - - ))} - - - - - - - - - - - - - {/* 统计信息 */} - - - - - - - - - 对话数 - - - {sessionsCount} - - - - - - - - - - - - - - - 消息数 - - - {messagesCount} - - - - - - - - - - - - - - - 已选工具 - - - {selectedTools.length} - - - - - - - - - - - - - - - )} - - ); -}; - -export default RightSidebar; diff --git a/src/views/AgentChat/components/RightSidebar/index.tsx b/src/views/AgentChat/components/RightSidebar/index.tsx new file mode 100644 index 00000000..cc4792be --- /dev/null +++ b/src/views/AgentChat/components/RightSidebar/index.tsx @@ -0,0 +1,240 @@ +// src/views/AgentChat/components/RightSidebar/index.tsx +// 右侧栏组件 - 配置中心(重构版本) + +import React from 'react'; +import { motion, AnimatePresence } from 'framer-motion'; +import { + Box, + Tooltip, + IconButton, + Tabs, + TabList, + TabPanels, + Tab, + TabPanel, + Badge, + HStack, + Text, +} from '@chakra-ui/react'; +import { + Settings, + ChevronRight, + Cpu, + Code, + BarChart3, +} from 'lucide-react'; +import { animations } from '../../constants/animations'; +import ModelSelector from './ModelSelector'; +import ToolSelector from './ToolSelector'; +import Statistics from './Statistics'; + +/** + * RightSidebar 组件的 Props 类型 + */ +interface RightSidebarProps { + /** 侧边栏是否展开 */ + isOpen: boolean; + /** 关闭侧边栏回调 */ + onClose: () => void; + /** 当前选中的模型 ID */ + selectedModel: string; + /** 模型切换回调 */ + onModelChange: (modelId: string) => void; + /** 已选工具 ID 列表 */ + selectedTools: string[]; + /** 工具选择变化回调 */ + onToolsChange: (tools: string[]) => void; + /** 会话总数 */ + sessionsCount: number; + /** 消息总数 */ + messagesCount: number; +} + +/** + * RightSidebar - 右侧栏组件(配置中心)(重构版本) + * + * 架构改进: + * - 模型选择提取到 ModelSelector 组件(120 行) + * - 工具选择提取到 ToolSelector 组件(200 行) + * - 统计信息提取到 Statistics 组件(100 行) + * - 主组件只负责 Tabs 管理和布局组合(150 行) + * + * 主组件职责: + * 1. 管理 Tabs 切换(模型/工具/统计) + * 2. 渲染标题栏(配置中心 + 收起按钮) + * 3. 组合三个子组件(TabPanels) + * 4. 处理侧边栏动画(滑入/滑出) + */ +const RightSidebar: React.FC = ({ + isOpen, + onClose, + selectedModel, + onModelChange, + selectedTools, + onToolsChange, + sessionsCount, + messagesCount, +}) => { + return ( + + {isOpen && ( + + + {/* ==================== 标题栏 ==================== */} + + + {/* 左侧:标题 */} + + + + 配置中心 + + + + {/* 右侧:收起按钮 */} + + + } + onClick={onClose} + aria-label="收起侧边栏" + 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', + }} + /> + + + + + + {/* ==================== Tab 面板 ==================== */} + + + {/* Tab 标签栏 */} + + {/* 模型 Tab */} + + + + 模型 + + + + {/* 工具 Tab */} + + + + 工具 + {selectedTools.length > 0 && ( + + {selectedTools.length} + + )} + + + + {/* 统计 Tab */} + + + + 统计 + + + + + {/* Tab 内容面板 */} + + {/* 模型选择面板 */} + + + + + {/* 工具选择面板 */} + + + + + {/* 统计信息面板 */} + + + + + + + + + )} + + ); +}; + +export default RightSidebar; diff --git a/src/views/AgentChat/components/RightSidebar/types.ts b/src/views/AgentChat/components/RightSidebar/types.ts new file mode 100644 index 00000000..976b55cd --- /dev/null +++ b/src/views/AgentChat/components/RightSidebar/types.ts @@ -0,0 +1,27 @@ +// src/views/AgentChat/components/RightSidebar/types.ts +// RightSidebar 组件的 TypeScript 类型定义 + +/** + * 模型数据结构(来自 constants/models) + */ +export interface Model { + id: string; + name: string; + description: string; + icon: React.ReactNode; +} + +/** + * 工具数据结构(来自 constants/tools) + */ +export interface Tool { + id: string; + name: string; + description: string; + icon: React.ReactNode; +} + +/** + * 工具分类(Map<分类名, 工具列表>) + */ +export type ToolCategories = Record;