- 实现Agent管理,支持AI辅助生成系统提示词 - 支持多个AI提供商(OpenRouter、智谱、MiniMax等) - 实现聊天室和讨论引擎 - WebSocket实时消息推送 - 前端使用React + Ant Design - 后端使用FastAPI + MongoDB Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
246 lines
7.3 KiB
TypeScript
246 lines
7.3 KiB
TypeScript
/**
|
|
* 讨论历史页面
|
|
*/
|
|
import React, { useEffect, useState } from 'react'
|
|
import {
|
|
Table, Card, Tag, Typography, Space, Button,
|
|
Modal, List, Descriptions, Progress, Empty
|
|
} from 'antd'
|
|
import {
|
|
CheckCircleOutlined, CloseCircleOutlined,
|
|
EyeOutlined, RobotOutlined
|
|
} from '@ant-design/icons'
|
|
import { discussionApi } from '../services/api'
|
|
import type { DiscussionResult } from '../types'
|
|
import dayjs from 'dayjs'
|
|
|
|
const { Title, Text, Paragraph } = Typography
|
|
|
|
const DiscussionHistory: React.FC = () => {
|
|
const [discussions, setDiscussions] = useState<DiscussionResult[]>([])
|
|
const [total, setTotal] = useState(0)
|
|
const [loading, setLoading] = useState(false)
|
|
const [detailVisible, setDetailVisible] = useState(false)
|
|
const [selectedDiscussion, setSelectedDiscussion] = useState<DiscussionResult | null>(null)
|
|
|
|
const fetchDiscussions = async (page = 1, pageSize = 20) => {
|
|
setLoading(true)
|
|
try {
|
|
const result = await discussionApi.list(undefined, pageSize)
|
|
setDiscussions(result.discussions)
|
|
setTotal(result.total)
|
|
} catch (e) {
|
|
console.error('Failed to fetch discussions:', e)
|
|
} finally {
|
|
setLoading(false)
|
|
}
|
|
}
|
|
|
|
useEffect(() => {
|
|
fetchDiscussions()
|
|
}, [])
|
|
|
|
const showDetail = (record: DiscussionResult) => {
|
|
setSelectedDiscussion(record)
|
|
setDetailVisible(true)
|
|
}
|
|
|
|
const columns = [
|
|
{
|
|
title: '讨论目标',
|
|
dataIndex: 'objective',
|
|
key: 'objective',
|
|
width: 300,
|
|
ellipsis: true
|
|
},
|
|
{
|
|
title: '状态',
|
|
dataIndex: 'consensus_reached',
|
|
key: 'consensus_reached',
|
|
width: 120,
|
|
render: (reached: boolean, record: DiscussionResult) => (
|
|
<Space>
|
|
{reached ? (
|
|
<Tag color="success" icon={<CheckCircleOutlined />}>达成共识</Tag>
|
|
) : (
|
|
<Tag color="default" icon={<CloseCircleOutlined />}>未达成</Tag>
|
|
)}
|
|
</Space>
|
|
)
|
|
},
|
|
{
|
|
title: '置信度',
|
|
dataIndex: 'confidence',
|
|
key: 'confidence',
|
|
width: 120,
|
|
render: (confidence: number) => (
|
|
<Progress
|
|
percent={Math.round(confidence * 100)}
|
|
size="small"
|
|
strokeColor={confidence >= 0.8 ? '#52c41a' : confidence >= 0.5 ? '#faad14' : '#ff4d4f'}
|
|
/>
|
|
)
|
|
},
|
|
{
|
|
title: '轮数',
|
|
dataIndex: 'total_rounds',
|
|
key: 'total_rounds',
|
|
width: 80
|
|
},
|
|
{
|
|
title: '消息数',
|
|
dataIndex: 'total_messages',
|
|
key: 'total_messages',
|
|
width: 80
|
|
},
|
|
{
|
|
title: '参与Agent',
|
|
dataIndex: 'participating_agents',
|
|
key: 'participating_agents',
|
|
width: 150,
|
|
render: (agents: string[]) => (
|
|
<Text type="secondary">{agents.length} 个</Text>
|
|
)
|
|
},
|
|
{
|
|
title: '时间',
|
|
dataIndex: 'created_at',
|
|
key: 'created_at',
|
|
width: 180,
|
|
render: (time: string) => dayjs(time).format('YYYY-MM-DD HH:mm')
|
|
},
|
|
{
|
|
title: '操作',
|
|
key: 'actions',
|
|
width: 80,
|
|
render: (_: unknown, record: DiscussionResult) => (
|
|
<Button
|
|
type="link"
|
|
icon={<EyeOutlined />}
|
|
onClick={() => showDetail(record)}
|
|
>
|
|
详情
|
|
</Button>
|
|
)
|
|
}
|
|
]
|
|
|
|
return (
|
|
<div style={{ marginLeft: 200 }}>
|
|
<Title level={2}>讨论历史</Title>
|
|
|
|
<Card>
|
|
<Table
|
|
dataSource={discussions}
|
|
columns={columns}
|
|
rowKey="discussion_id"
|
|
loading={loading}
|
|
pagination={{
|
|
total,
|
|
pageSize: 20,
|
|
showTotal: (t) => `共 ${t} 条记录`
|
|
}}
|
|
/>
|
|
</Card>
|
|
|
|
{/* 详情弹窗 */}
|
|
<Modal
|
|
title="讨论详情"
|
|
open={detailVisible}
|
|
onCancel={() => setDetailVisible(false)}
|
|
footer={null}
|
|
width={800}
|
|
>
|
|
{selectedDiscussion && (
|
|
<div>
|
|
<Descriptions bordered column={2}>
|
|
<Descriptions.Item label="讨论目标" span={2}>
|
|
{selectedDiscussion.objective}
|
|
</Descriptions.Item>
|
|
<Descriptions.Item label="状态">
|
|
{selectedDiscussion.consensus_reached ? (
|
|
<Tag color="success">达成共识</Tag>
|
|
) : (
|
|
<Tag color="default">未达成共识</Tag>
|
|
)}
|
|
</Descriptions.Item>
|
|
<Descriptions.Item label="置信度">
|
|
<Progress
|
|
percent={Math.round(selectedDiscussion.confidence * 100)}
|
|
size="small"
|
|
style={{ width: 150 }}
|
|
/>
|
|
</Descriptions.Item>
|
|
<Descriptions.Item label="总轮数">
|
|
{selectedDiscussion.total_rounds}
|
|
</Descriptions.Item>
|
|
<Descriptions.Item label="总消息数">
|
|
{selectedDiscussion.total_messages}
|
|
</Descriptions.Item>
|
|
<Descriptions.Item label="结束原因" span={2}>
|
|
{selectedDiscussion.end_reason || '无'}
|
|
</Descriptions.Item>
|
|
<Descriptions.Item label="开始时间">
|
|
{dayjs(selectedDiscussion.created_at).format('YYYY-MM-DD HH:mm:ss')}
|
|
</Descriptions.Item>
|
|
<Descriptions.Item label="结束时间">
|
|
{selectedDiscussion.completed_at
|
|
? dayjs(selectedDiscussion.completed_at).format('YYYY-MM-DD HH:mm:ss')
|
|
: '进行中'}
|
|
</Descriptions.Item>
|
|
</Descriptions>
|
|
|
|
<Card title="结果摘要" style={{ marginTop: 16 }}>
|
|
<Paragraph>{selectedDiscussion.summary || '暂无摘要'}</Paragraph>
|
|
</Card>
|
|
|
|
<Card title="行动项" style={{ marginTop: 16 }}>
|
|
{selectedDiscussion.action_items.length > 0 ? (
|
|
<List
|
|
dataSource={selectedDiscussion.action_items}
|
|
renderItem={(item) => (
|
|
<List.Item>
|
|
<CheckCircleOutlined style={{ color: '#52c41a', marginRight: 8 }} />
|
|
{item}
|
|
</List.Item>
|
|
)}
|
|
/>
|
|
) : (
|
|
<Empty description="暂无行动项" />
|
|
)}
|
|
</Card>
|
|
|
|
<Card title="未解决问题" style={{ marginTop: 16 }}>
|
|
{selectedDiscussion.unresolved_issues.length > 0 ? (
|
|
<List
|
|
dataSource={selectedDiscussion.unresolved_issues}
|
|
renderItem={(item) => (
|
|
<List.Item>
|
|
<CloseCircleOutlined style={{ color: '#faad14', marginRight: 8 }} />
|
|
{item}
|
|
</List.Item>
|
|
)}
|
|
/>
|
|
) : (
|
|
<Empty description="无未解决问题" />
|
|
)}
|
|
</Card>
|
|
|
|
<Card title="Agent贡献" style={{ marginTop: 16 }}>
|
|
<Space wrap>
|
|
{Object.entries(selectedDiscussion.agent_contributions).map(([agentId, count]) => (
|
|
<Tag key={agentId} icon={<RobotOutlined />}>
|
|
{agentId}: {count}条消息
|
|
</Tag>
|
|
))}
|
|
</Space>
|
|
</Card>
|
|
</div>
|
|
)}
|
|
</Modal>
|
|
</div>
|
|
)
|
|
}
|
|
|
|
export default DiscussionHistory
|