From 80084d607b79b41697f7205180eec57ee1440af8 Mon Sep 17 00:00:00 2001 From: zdl <3489966805@qq.com> Date: Mon, 24 Nov 2025 15:11:19 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=20LeftSidebar=20(~280=20=E8=A1=8C)=20-?= =?UTF-8?q?=20=E5=AF=B9=E8=AF=9D=E5=8E=86=E5=8F=B2=E5=88=97=E8=A1=A8=20+?= =?UTF-8?q?=20=E7=94=A8=E6=88=B7=E4=BF=A1=E6=81=AF=E5=8D=A1=E7=89=87?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../components/LeftSidebar/SessionCard.js | 76 +++++ .../AgentChat/components/LeftSidebar/index.js | 313 ++++++++++++++++++ 2 files changed, 389 insertions(+) create mode 100644 src/views/AgentChat/components/LeftSidebar/SessionCard.js create mode 100644 src/views/AgentChat/components/LeftSidebar/index.js diff --git a/src/views/AgentChat/components/LeftSidebar/SessionCard.js b/src/views/AgentChat/components/LeftSidebar/SessionCard.js new file mode 100644 index 00000000..63a4ef23 --- /dev/null +++ b/src/views/AgentChat/components/LeftSidebar/SessionCard.js @@ -0,0 +1,76 @@ +// src/views/AgentChat/components/LeftSidebar/SessionCard.js +// 会话卡片组件 + +import React from 'react'; +import { motion } from 'framer-motion'; +import { Card, CardBody, Flex, Box, Text, Badge } from '@chakra-ui/react'; + +/** + * SessionCard - 会话卡片组件 + * + * @param {Object} props + * @param {Object} props.session - 会话数据 + * @param {boolean} props.isActive - 是否为当前选中的会话 + * @param {Function} props.onPress - 点击回调函数 + * @returns {JSX.Element} + */ +const SessionCard = ({ session, isActive, onPress }) => { + return ( + + + + + + + {session.title || '新对话'} + + + {new Date(session.created_at || session.timestamp).toLocaleString('zh-CN', { + month: 'numeric', + day: 'numeric', + hour: '2-digit', + minute: '2-digit', + })} + + + {session.message_count && ( + + {session.message_count} + + )} + + + + + ); +}; + +export default SessionCard; diff --git a/src/views/AgentChat/components/LeftSidebar/index.js b/src/views/AgentChat/components/LeftSidebar/index.js new file mode 100644 index 00000000..9f9e810d --- /dev/null +++ b/src/views/AgentChat/components/LeftSidebar/index.js @@ -0,0 +1,313 @@ +// src/views/AgentChat/components/LeftSidebar/index.js +// 左侧栏组件 - 对话历史列表 + +import React, { useState } from 'react'; +import { motion, AnimatePresence } from 'framer-motion'; +import { + Box, + Text, + Input, + Avatar, + Badge, + Spinner, + Tooltip, + IconButton, + HStack, + VStack, + Flex, +} from '@chakra-ui/react'; +import { MessageSquare, Plus, Search, ChevronLeft } from 'lucide-react'; +import { animations } from '../../constants/animations'; +import { groupSessionsByDate } from '../../utils/sessionUtils'; +import SessionCard from './SessionCard'; + +/** + * LeftSidebar - 左侧栏组件 + * + * @param {Object} props + * @param {boolean} props.isOpen - 侧边栏是否展开 + * @param {Function} props.onClose - 关闭侧边栏回调 + * @param {Array} props.sessions - 会话列表 + * @param {string|null} props.currentSessionId - 当前选中的会话 ID + * @param {Function} props.onSessionSwitch - 切换会话回调 + * @param {Function} props.onNewSession - 新建会话回调 + * @param {boolean} props.isLoadingSessions - 会话加载中状态 + * @param {Object} props.user - 用户信息 + * @returns {JSX.Element|null} + */ +const LeftSidebar = ({ + isOpen, + onClose, + sessions, + currentSessionId, + onSessionSwitch, + onNewSession, + isLoadingSessions, + user, +}) => { + const [searchQuery, setSearchQuery] = useState(''); + + // 按日期分组会话 + const sessionGroups = groupSessionsByDate(sessions); + + // 搜索过滤 + const filteredSessions = searchQuery + ? sessions.filter( + (s) => + s.title?.toLowerCase().includes(searchQuery.toLowerCase()) || + s.session_id?.toLowerCase().includes(searchQuery.toLowerCase()) + ) + : sessions; + + return ( + + {isOpen && ( + + + {/* 标题栏 */} + + + + + + 对话历史 + + + + + + } + onClick={onNewSession} + 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(59, 130, 246, 0.2)', + borderColor: 'blue.400', + color: 'blue.300', + boxShadow: '0 0 12px rgba(59, 130, 246, 0.3)', + }} + /> + + + + + } + 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', + }} + /> + + + + + + {/* 搜索框 */} + + + + + setSearchQuery(e.target.value)} + size="sm" + variant="outline" + pl={10} + 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)', + }} + /> + + + + {/* 会话列表 */} + + {/* 按日期分组显示会话 */} + {sessionGroups.today.length > 0 && ( + + + 今天 + + + {sessionGroups.today.map((session, idx) => ( + + onSessionSwitch(session.session_id)} + /> + + ))} + + + )} + + {sessionGroups.yesterday.length > 0 && ( + + + 昨天 + + + {sessionGroups.yesterday.map((session) => ( + onSessionSwitch(session.session_id)} + /> + ))} + + + )} + + {sessionGroups.thisWeek.length > 0 && ( + + + 本周 + + + {sessionGroups.thisWeek.map((session) => ( + onSessionSwitch(session.session_id)} + /> + ))} + + + )} + + {sessionGroups.older.length > 0 && ( + + + 更早 + + + {sessionGroups.older.map((session) => ( + onSessionSwitch(session.session_id)} + /> + ))} + + + )} + + {/* 加载状态 */} + {isLoadingSessions && ( + + + + )} + + {/* 空状态 */} + {sessions.length === 0 && !isLoadingSessions && ( + + + 还没有对话历史 + 开始一个新对话吧! + + )} + + + {/* 用户信息卡片 */} + + + + + + {user?.nickname || '未登录'} + + + {user?.subscription_type || 'free'} + + + + + + + )} + + ); +}; + +export default LeftSidebar;