195 lines
7.7 KiB
TypeScript
195 lines
7.7 KiB
TypeScript
import {
|
||
ArrowRightOutlined,
|
||
CompassOutlined,
|
||
DeleteOutlined,
|
||
EditOutlined,
|
||
MessageOutlined,
|
||
RobotOutlined,
|
||
} from '@ant-design/icons';
|
||
import { Button, Col, Row, Empty, Popconfirm, App as AntApp, Tag, Space } from 'antd';
|
||
import { Link, useNavigate } from 'react-router-dom';
|
||
import dayjs from 'dayjs';
|
||
import type { AgentListLogicOutput } from '../AgentListLogic';
|
||
import './AgentListWeb.css';
|
||
|
||
interface Props {
|
||
logic: AgentListLogicOutput;
|
||
}
|
||
|
||
export default function AgentListWeb({ logic }: Props) {
|
||
const { message } = AntApp.useApp();
|
||
const navigate = useNavigate();
|
||
const { list, loading, stats, handleDelete, isImageUrl, getModelLabel } = logic;
|
||
|
||
return (
|
||
<div className="page-container">
|
||
<div className="agent-list-header">
|
||
<div className="agent-list-header-content">
|
||
<div className="agent-list-intro">
|
||
<div className="agent-list-badge">
|
||
<RobotOutlined className="agent-list-badge-icon" />
|
||
我的 Agent 资产
|
||
</div>
|
||
|
||
<h2 className="page-title" style={{ marginBottom: 10 }}>
|
||
我的智能体
|
||
</h2>
|
||
<div className="page-subtitle" style={{ marginTop: 0, fontSize: 15, lineHeight: 1.75 }}>
|
||
把你的 AI 助手沉淀成一组可管理、可协作、可持续进化的能力单元。创建入口统一在智能体广场,这里负责查看、进入和运营它们。
|
||
</div>
|
||
</div>
|
||
<Button
|
||
type="primary"
|
||
size="large"
|
||
icon={<CompassOutlined />}
|
||
onClick={() => navigate('/agents/new')}
|
||
style={{ borderRadius: 14, height: 46, padding: '0 18px', fontWeight: 600 }}
|
||
>
|
||
创建智能体
|
||
</Button>
|
||
</div>
|
||
|
||
<div className="agent-list-stats-grid">
|
||
{stats.map((item) => (
|
||
<div key={item.label} className="agent-list-stat-card">
|
||
<div className="agent-list-stat-label">{item.label}</div>
|
||
<div className="agent-list-stat-content">
|
||
<span className="agent-list-stat-value">{item.value}</span>
|
||
<span
|
||
className="agent-list-stat-badge"
|
||
style={{
|
||
background: item.tone,
|
||
color: item.color,
|
||
}}
|
||
>
|
||
实时统计
|
||
</span>
|
||
</div>
|
||
</div>
|
||
))}
|
||
</div>
|
||
</div>
|
||
|
||
{!loading && list.length === 0 ? (
|
||
<div className="empty-state">
|
||
<Empty description="你还没有任何智能体">
|
||
<Button type="primary" onClick={() => navigate('/agents/new')} style={{ borderRadius: 10 }}>
|
||
创建智能体
|
||
</Button>
|
||
</Empty>
|
||
</div>
|
||
) : (
|
||
<Row gutter={[18, 18]}>
|
||
{list.map((a) => {
|
||
const modelLabel = getModelLabel(a.model);
|
||
return (
|
||
<Col xs={24} sm={12} md={8} lg={6} key={a.id}>
|
||
<div className="agent-card">
|
||
<div className="agent-card-header">
|
||
<div
|
||
className="agent-card-avatar"
|
||
style={{ background: a.avatar || 'var(--gradient-brand)' }}
|
||
>
|
||
{isImageUrl(a.avatar) ? (
|
||
<img src={a.avatar} className="w-full h-full object-cover" alt="avatar" />
|
||
) : (
|
||
(a.name?.charAt(0) || '?').toUpperCase()
|
||
)}
|
||
</div>
|
||
<div className="agent-card-title-group">
|
||
<div className="agent-card-name">{a.name}</div>
|
||
<div className="agent-card-update-time">
|
||
最近更新于 {dayjs(a.updated_at).format('YYYY-MM-DD')}
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<div className="agent-card-desc-container">
|
||
<div className="agent-card-desc">
|
||
{a.description || '还没有填写描述,可以补充这个智能体适合解决什么问题。'}
|
||
</div>
|
||
</div>
|
||
|
||
<Space size={6} wrap className="agent-card-tags">
|
||
{a.visibility === 'public' && (
|
||
<Tag bordered={false} style={{ background: 'var(--color-success-soft)', color: 'var(--color-success)', borderRadius: 999, margin: 0 }}>
|
||
公开
|
||
</Tag>
|
||
)}
|
||
{a.visibility === 'team' && (
|
||
<Tag bordered={false} style={{ background: 'var(--color-info-soft)', color: 'var(--color-info)', borderRadius: 999, margin: 0 }}>
|
||
团队
|
||
</Tag>
|
||
)}
|
||
{a.visibility === 'private' && (
|
||
<Tag bordered={false} style={{ background: 'var(--color-surface-2)', color: 'var(--color-text-secondary)', borderRadius: 999, margin: 0 }}>
|
||
私有
|
||
</Tag>
|
||
)}
|
||
{modelLabel && (
|
||
<Tag
|
||
bordered={false}
|
||
className="agent-card-tag-model"
|
||
style={{ background: 'var(--color-brand-soft)', color: 'var(--color-brand)', borderRadius: 999, margin: 0, maxWidth: '100%' }}
|
||
>
|
||
<span className="agent-card-tag-model-text">
|
||
{modelLabel}
|
||
</span>
|
||
</Tag>
|
||
)}
|
||
{(a.fork_count ?? 0) > 0 && (
|
||
<Tag bordered={false} style={{ background: 'var(--color-surface-2)', color: 'var(--color-text-secondary)', borderRadius: 999, margin: 0 }}>
|
||
Fork {a.fork_count}
|
||
</Tag>
|
||
)}
|
||
</Space>
|
||
|
||
<div className="agent-card-actions">
|
||
<Link to={`/chat/${a.id}`} style={{ flex: 1 }}>
|
||
<Button type="primary" block icon={<MessageOutlined />} style={{ borderRadius: 12, height: 40, fontWeight: 600 }}>
|
||
聊天
|
||
</Button>
|
||
</Link>
|
||
<Link to={`/agents/${a.id}`} style={{ flex: 1 }}>
|
||
<Button block icon={<EditOutlined />} style={{ borderRadius: 12, height: 40 }}>
|
||
管理
|
||
</Button>
|
||
</Link>
|
||
<Popconfirm
|
||
title="确定删除该智能体?"
|
||
description="将删除其知识库与对话记录"
|
||
onConfirm={() => {
|
||
handleDelete(a.id);
|
||
message.success('已删除');
|
||
}}
|
||
okText="删除"
|
||
cancelText="取消"
|
||
>
|
||
<Button danger icon={<DeleteOutlined />} style={{ borderRadius: 12, width: 40, height: 40 }} />
|
||
</Popconfirm>
|
||
</div>
|
||
</div>
|
||
</Col>
|
||
)})}
|
||
</Row>
|
||
)}
|
||
|
||
{list.length > 0 && (
|
||
<div className="agent-list-banner">
|
||
<div>
|
||
<div className="agent-list-banner-title">
|
||
想创建新的智能体入口?
|
||
</div>
|
||
<div className="agent-list-banner-desc">
|
||
统一从智能体广场进入,保证创建流程和发现体验保持一致。
|
||
</div>
|
||
</div>
|
||
<Button type="text" icon={<ArrowRightOutlined />} onClick={() => navigate('/marketplace')} style={{ color: 'var(--color-brand)', fontWeight: 600 }}>
|
||
去广场继续发现
|
||
</Button>
|
||
</div>
|
||
)}
|
||
</div>
|
||
);
|
||
}
|