feat(aia): Complete AIA V2.0 with universal streaming capabilities
Major Updates: - Add StreamingService with OpenAI Compatible format (backend/common/streaming) - Upgrade Chat component V2 with Ant Design X integration - Implement AIA module with 12 intelligent agents - Create AgentHub with 100% prototype V11 restoration - Create ChatWorkspace with streaming response support - Add ThinkingBlock for deep thinking display - Add useAIStream Hook for OpenAI Compatible stream handling Backend Common Capabilities (~400 lines): - OpenAIStreamAdapter: SSE adapter with OpenAI format - StreamingService: unified streaming service - Support content and reasoning_content dual streams - Deep thinking tag processing (<think>...</think>) Frontend Common Capabilities (~2000 lines): - AIStreamChat: modern streaming chat component - ThinkingBlock: collapsible deep thinking display - ConversationList: conversation management with grouping - useAIStream: OpenAI Compatible stream handler Hook - useConversations: conversation state management Hook - Modern design styles (Ultramodern theme) AIA Module Frontend (~1500 lines): - AgentHub: 12 agent cards with timeline design - ChatWorkspace: fullscreen immersive chat interface - AgentCard: theme-colored cards (blue/yellow/teal/purple) - 5 phases, 12 agents configuration - Responsive layout (desktop + mobile) AIA Module Backend (~900 lines): - agentService: 12 agents config with system prompts - conversationService: refactored with StreamingService - attachmentService: file upload skeleton (30k token limit) - 12 API endpoints with authentication - Full CRUD for conversations and messages Documentation: - AIA module status and development guide - Universal capabilities catalog (11 services) - Quick reference card for developers - System overview updates Testing: - Stream response verified (HTTP 200) - Authentication working correctly - Auto conversation creation working - Deep thinking display working - Message input and send working Status: Core features completed (85%), attachment and history loading pending
This commit is contained in:
169
frontend-v2/src/shared/components/Chat/ConversationList.tsx
Normal file
169
frontend-v2/src/shared/components/Chat/ConversationList.tsx
Normal file
@@ -0,0 +1,169 @@
|
||||
/**
|
||||
* ConversationList - 会话列表组件
|
||||
*
|
||||
* 现代感设计的会话列表,支持:
|
||||
* - 分组显示(今天、昨天、更早)
|
||||
* - 新建会话
|
||||
* - 会话切换
|
||||
* - 会话删除
|
||||
* - 智能体图标
|
||||
*/
|
||||
|
||||
import React, { useMemo } from 'react';
|
||||
import { Button, Typography, Dropdown, Empty } from 'antd';
|
||||
import {
|
||||
PlusOutlined,
|
||||
MessageOutlined,
|
||||
DeleteOutlined,
|
||||
MoreOutlined,
|
||||
RobotOutlined,
|
||||
} from '@ant-design/icons';
|
||||
import type { Conversation, ConversationGroup } from './hooks/useConversations';
|
||||
import './styles/conversation-list.css';
|
||||
|
||||
const { Text } = Typography;
|
||||
|
||||
/**
|
||||
* ConversationList Props
|
||||
*/
|
||||
export interface ConversationListProps {
|
||||
/** 分组会话列表 */
|
||||
groups: ConversationGroup[];
|
||||
/** 当前会话 ID */
|
||||
currentId: string | null;
|
||||
/** 会话点击回调 */
|
||||
onSelect: (id: string) => void;
|
||||
/** 新建会话回调 */
|
||||
onNew: () => void;
|
||||
/** 删除会话回调 */
|
||||
onDelete?: (id: string) => void;
|
||||
/** 标题 */
|
||||
title?: string;
|
||||
/** Logo */
|
||||
logo?: React.ReactNode;
|
||||
/** 自定义类名 */
|
||||
className?: string;
|
||||
/** 是否加载中 */
|
||||
loading?: boolean;
|
||||
}
|
||||
|
||||
/**
|
||||
* 会话列表组件
|
||||
*/
|
||||
export const ConversationList: React.FC<ConversationListProps> = ({
|
||||
groups,
|
||||
currentId,
|
||||
onSelect,
|
||||
onNew,
|
||||
onDelete,
|
||||
title = 'AI 助手',
|
||||
logo,
|
||||
className = '',
|
||||
loading = false,
|
||||
}) => {
|
||||
// 会话项菜单
|
||||
const getMenuItems = (conv: Conversation) => [
|
||||
{
|
||||
key: 'delete',
|
||||
icon: <DeleteOutlined />,
|
||||
label: '删除对话',
|
||||
danger: true,
|
||||
onClick: () => onDelete?.(conv.id),
|
||||
},
|
||||
];
|
||||
|
||||
// 是否为空
|
||||
const isEmpty = useMemo(() => {
|
||||
return groups.every(g => g.conversations.length === 0);
|
||||
}, [groups]);
|
||||
|
||||
return (
|
||||
<div className={`conversation-list ${className}`}>
|
||||
{/* 头部 */}
|
||||
<div className="conversation-list-header">
|
||||
<div className="conversation-list-logo">
|
||||
{logo || <RobotOutlined className="default-logo" />}
|
||||
<span className="conversation-list-title">{title}</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* 新建会话按钮 */}
|
||||
<div className="conversation-list-new">
|
||||
<Button
|
||||
type="default"
|
||||
icon={<PlusOutlined />}
|
||||
onClick={onNew}
|
||||
block
|
||||
className="new-conversation-btn"
|
||||
>
|
||||
新对话
|
||||
</Button>
|
||||
</div>
|
||||
|
||||
{/* 会话列表 */}
|
||||
<div className="conversation-list-content">
|
||||
{isEmpty ? (
|
||||
<Empty
|
||||
image={Empty.PRESENTED_IMAGE_SIMPLE}
|
||||
description="暂无对话"
|
||||
className="conversation-empty"
|
||||
/>
|
||||
) : (
|
||||
groups.map(group => (
|
||||
<div key={group.key} className="conversation-group">
|
||||
<div className="conversation-group-label">
|
||||
<Text type="secondary">{group.label}</Text>
|
||||
</div>
|
||||
|
||||
{group.conversations.map(conv => (
|
||||
<div
|
||||
key={conv.id}
|
||||
className={`conversation-item ${currentId === conv.id ? 'active' : ''}`}
|
||||
onClick={() => onSelect(conv.id)}
|
||||
>
|
||||
<div className="conversation-item-icon">
|
||||
{conv.agentIcon ? (
|
||||
<span className="agent-icon">{conv.agentIcon}</span>
|
||||
) : (
|
||||
<MessageOutlined />
|
||||
)}
|
||||
</div>
|
||||
|
||||
<div className="conversation-item-content">
|
||||
<div className="conversation-item-title">
|
||||
{conv.title || '新对话'}
|
||||
</div>
|
||||
{conv.lastMessage && (
|
||||
<div className="conversation-item-preview">
|
||||
{conv.lastMessage}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
|
||||
{onDelete && (
|
||||
<Dropdown
|
||||
menu={{ items: getMenuItems(conv) }}
|
||||
trigger={['click']}
|
||||
placement="bottomRight"
|
||||
>
|
||||
<Button
|
||||
type="text"
|
||||
size="small"
|
||||
icon={<MoreOutlined />}
|
||||
className="conversation-item-more"
|
||||
onClick={(e) => e.stopPropagation()}
|
||||
/>
|
||||
</Dropdown>
|
||||
)}
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
))
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default ConversationList;
|
||||
|
||||
Reference in New Issue
Block a user