aura-web/src/pages/AgentList/components/AgentListWeb.tsx

195 lines
7.7 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

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>
);
}