From 577dceebfe789cf83088959a0aada6fd2e59dc43 Mon Sep 17 00:00:00 2001 From: "DESKTOP-72TV0V4\\caoxiaozhu" Date: Tue, 10 Mar 2026 16:09:09 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E6=96=B0=E5=A2=9E=20Chat=20=E8=81=8A?= =?UTF-8?q?=E5=A4=A9=E9=A1=B5=E9=9D=A2=E5=B9=B6=E4=BC=98=E5=8C=96=20Agents?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 新增 Chat.vue 聊天页面组件 - 重构 Agents.vue 页面代码 - 更新侧边栏和路由配置 Co-Authored-By: Claude Opus 4.6 --- web/src/components/Sidebar.vue | 15 +- web/src/router/index.ts | 6 + web/src/views/Agents.vue | 556 +++++++++++---------------------- web/src/views/Chat.vue | 430 +++++++++++++++++++++++++ 4 files changed, 618 insertions(+), 389 deletions(-) create mode 100644 web/src/views/Chat.vue diff --git a/web/src/components/Sidebar.vue b/web/src/components/Sidebar.vue index d7166eb..d1e8165 100644 --- a/web/src/components/Sidebar.vue +++ b/web/src/components/Sidebar.vue @@ -41,7 +41,7 @@ interface MenuItem { // 第1组: Chat, Agents const group1 = computed(() => [ - { name: 'Chat', icon: 'fa-robot', path: '/agents' }, + { name: 'Chat', icon: 'fa-robot', path: '/chat' }, { name: 'Agents', icon: 'fa-users', badge: 3, path: '/agents' }, ]) @@ -68,11 +68,6 @@ const group4 = computed(() => [ const activeMenu = computed(() => { const currentPath = route.path - // Special case for /agents - prioritize Chat over Agents - if (currentPath === '/agents') { - return 'Chat' - } - // Check all groups const allGroups = [...group1.value, ...group2.value, ...group3.value, ...group4.value] const item = allGroups.find(item => item.path === currentPath) @@ -135,7 +130,7 @@ const handleUserCommand = (command: string) => {
  • {
  • {
  • {
  • -import { ref, nextTick } from 'vue' - -interface ChatMessage { - id: number - role: 'user' | 'assistant' - content: string - timestamp: Date - isStreaming?: boolean -} +import { ref, computed } from 'vue' interface Agent { id: number @@ -16,414 +8,220 @@ interface Agent { description: string accentColor: string gradient: string + status: 'running' | 'stopped' + framework: string + model: string + mcpServers: number + createdAt: string } -// AI 助手配置 +// 管理页面的 agents const agents = ref([ - { id: 1, name: 'Claude', avatar: '🧠', description: 'Anthropic AI', accentColor: '#f97316', gradient: 'from-orange-500/20 to-amber-500/20' }, - { id: 2, name: 'Gemini', avatar: '✨', description: 'Google DeepMind', accentColor: '#8b5cf6', gradient: 'from-violet-500/20 to-purple-500/20' }, - { id: 3, name: 'ChatGPT', avatar: '💬', description: 'OpenAI', accentColor: '#10b981', gradient: 'from-emerald-500/20 to-green-500/20' }, - { id: 4, name: 'DeepSeek', avatar: '🔮', description: 'DeepSeek AI', accentColor: '#3b82f6', gradient: 'from-blue-500/20 to-cyan-500/20' }, - { id: 5, name: 'Kimi', avatar: '🌙', description: 'Moonshot AI', accentColor: '#ec4899', gradient: 'from-pink-500/20 to-rose-500/20' }, - { id: 6, name: '文心一言', avatar: '🐉', description: 'Baidu', accentColor: '#ef4444', gradient: 'from-red-500/20 to-orange-500/20' }, - { id: 7, name: '通义千问', avatar: '☁️', description: 'Alibaba', accentColor: '#06b6d4', gradient: 'from-cyan-500/20 to-sky-500/20' }, + { id: 1, name: 'Claude Agent', avatar: '🧠', description: 'General purpose AI assistant', accentColor: '#f97316', gradient: 'from-orange-500/20 to-amber-500/20', status: 'running', framework: 'Google ADK', model: 'gemini-2.0-flash', mcpServers: 2, createdAt: '2025-04-10' }, + { id: 2, name: 'Code Assistant', avatar: '💻', description: 'Specialized in code generation', accentColor: '#3b82f6', gradient: 'from-blue-500/20 to-cyan-500/20', status: 'running', framework: 'OpenAI', model: 'gpt-4o', mcpServers: 1, createdAt: '2025-04-08' }, + { id: 3, name: 'Data Analyst', avatar: '📊', description: 'Data analysis and visualization', accentColor: '#10b981', gradient: 'from-emerald-500/20 to-green-500/20', status: 'stopped', framework: 'PydanticAI', model: 'gpt-4o-mini', mcpServers: 3, createdAt: '2025-04-05' }, + { id: 4, name: 'Research Bot', avatar: '🔬', description: 'Academic research assistant', accentColor: '#8b5cf6', gradient: 'from-violet-500/20 to-purple-500/20', status: 'running', framework: 'LangChain', model: 'claude-3-5-sonnet', mcpServers: 2, createdAt: '2025-04-12' }, + { id: 5, name: '客服助手', avatar: '🎧', description: 'Customer support agent', accentColor: '#ec4899', gradient: 'from-pink-500/20 to-rose-500/20', status: 'running', framework: 'Google ADK', model: 'gemini-1.5-pro', mcpServers: 4, createdAt: '2025-04-11' }, ]) -// 当前选中的助手 -const selectedAgent = ref(agents.value[0]) -const sidebarCollapsed = ref(false) +const searchQuery = ref('') +const filterStatus = ref('all') -// 聊天消息 -const messages = ref([ - { id: 1, role: 'assistant', content: '你好!我是 Claude,你的 AI 助手。有什么我可以帮助你的吗?', timestamp: new Date() }, -]) +// 过滤后的 agents +const filteredAgents = computed(() => { + return agents.value.filter(agent => { + const matchSearch = agent.name.toLowerCase().includes(searchQuery.value.toLowerCase()) || + agent.framework.toLowerCase().includes(searchQuery.value.toLowerCase()) + const matchStatus = filterStatus.value === 'all' || agent.status === filterStatus.value + return matchSearch && matchStatus + }) +}) -// 输入内容 -const inputMessage = ref('') -const isLoading = ref(false) -const messagesContainer = ref(null) +// 统计数据 +const stats = computed(() => ({ + total: agents.value.length, + running: agents.value.filter(a => a.status === 'running').length, + stopped: agents.value.filter(a => a.status === 'stopped').length, +})) -// 发送消息 -const sendMessage = async () => { - if (!inputMessage.value.trim() || isLoading.value) return - - const userContent = inputMessage.value.trim() - inputMessage.value = '' - - const userMessage: ChatMessage = { - id: Date.now(), - role: 'user', - content: userContent, - timestamp: new Date() - } - messages.value.push(userMessage) - - const aiMessage: ChatMessage = { - id: Date.now() + 1, - role: 'assistant', - content: '', - timestamp: new Date(), - isStreaming: true - } - messages.value.push(aiMessage) - - nextTick(() => scrollToBottom()) - - isLoading.value = true - const fullResponse = `我理解你发送了消息: "${userContent}" - -作为 AI 助手,我可以帮助你: -• 回答各种问题 -• 编写代码和调试 -• 分析和处理数据 -• 翻译和写作 -• 头脑风暴和创意建议 - -请告诉我你需要什么帮助?` - - let currentIndex = 0 - const words = fullResponse.split('') - - const streamInterval = setInterval(() => { - if (currentIndex < words.length) { - aiMessage.content += words[currentIndex] - currentIndex++ - nextTick(() => scrollToBottom()) - } else { - clearInterval(streamInterval) - aiMessage.isStreaming = false - isLoading.value = false - } - }, 30) -} - -// 滚动到底部 -const scrollToBottom = () => { - if (messagesContainer.value) { - messagesContainer.value.scrollTop = messagesContainer.value.scrollHeight +// 状态颜色 +const statusClass = (status: string) => { + switch (status) { + case 'running': return 'bg-primary-success' + case 'stopped': return 'bg-gray-500' + default: return 'bg-gray-500' } } -// 复制消息 -const copyMessage = (content: string) => { - navigator.clipboard.writeText(content) +// 切换状态 +const toggleStatus = (agent: Agent) => { + agent.status = agent.status === 'running' ? 'stopped' : 'running' } -// 选择助手 -const selectAgent = (agent: Agent) => { - selectedAgent.value = agent - messages.value = [ - { id: 1, role: 'assistant', content: `你好!我是 ${agent.name}。有什么我可以帮助你的吗?`, timestamp: new Date() } - ] -} - -// 新建聊天 -const newChat = () => { - messages.value = [ - { id: 1, role: 'assistant', content: `你好!我是 ${selectedAgent.value?.name || 'Claude'}。有什么我可以帮助你的吗?`, timestamp: new Date() } - ] -} - -// 格式化时间 -const formatTime = (date: Date) => { - return date.toLocaleTimeString('zh-CN', { hour: '2-digit', minute: '2-digit' }) -} - -// 回车发送 -const handleKeydown = (e: KeyboardEvent) => { - if (e.key === 'Enter' && !e.shiftKey) { - e.preventDefault() - sendMessage() - } -} - -// 调整输入框高度 -const autoResize = (e: Event) => { - const target = e.target as HTMLTextAreaElement - target.style.height = 'auto' - target.style.height = Math.min(target.scrollHeight, 160) + 'px' -} - -// 切换侧边栏 -const toggleSidebar = () => { - sidebarCollapsed.value = !sidebarCollapsed.value - setTimeout(() => { - scrollToBottom() - }, 350) +// 删除 Agent +const deleteAgent = (id: number) => { + agents.value = agents.value.filter(a => a.id !== id) } - - diff --git a/web/src/views/Chat.vue b/web/src/views/Chat.vue new file mode 100644 index 0000000..6b89da5 --- /dev/null +++ b/web/src/views/Chat.vue @@ -0,0 +1,430 @@ + + + + +