(feature)(webapp) agent defaults to list mode, supports switching to card mode (#362)

This commit is contained in:
williamhliu
2023-11-10 18:21:59 +08:00
committed by GitHub
parent f998f27c6f
commit bd541e1199
6 changed files with 263 additions and 93 deletions

View File

@@ -1,12 +1,11 @@
import { DeleteOutlined, EditOutlined, PlusOutlined, UserOutlined } from '@ant-design/icons';
import { Button, Input, Popconfirm, Switch } from 'antd';
import { Button, Popconfirm, Switch, Table } from 'antd';
import classNames from 'classnames';
import moment from 'moment';
import { useEffect, useState } from 'react';
import styles from './style.less';
import { AgentType } from './type';
const { Search } = Input;
type Props = {
agents: AgentType[];
currentAgent?: AgentType;
@@ -25,33 +24,108 @@ const AgentsSection: React.FC<Props> = ({
onEditAgent,
onSaveAgent,
}) => {
// const [searchName, setSearchName] = useState('');
const [showAgents, setShowAgents] = useState<AgentType[]>([]);
const [showType, setShowType] = useState(localStorage.getItem('AGENT_SHOW_TYPE') || 'list');
useEffect(() => {
setShowAgents(agents);
}, [agents]);
const columns = [
{
title: '助理名称',
dataIndex: 'name',
key: 'name',
render: (value: string, agent: AgentType) => {
return (
<a
onClick={() => {
onSelectAgent(agent);
}}
>
{value}
</a>
);
},
},
{
title: '描述',
dataIndex: 'description',
key: 'description',
},
{
title: '状态',
dataIndex: 'status',
key: 'status',
render: (status: number, agent: AgentType) => {
return (
<div className={styles.toggleStatus}>
{status === 0 ? '已禁用' : <span className={styles.online}></span>}
<span
onClick={(e) => {
e.stopPropagation();
}}
>
<Switch
size="small"
defaultChecked={status === 1}
onChange={(value) => {
onSaveAgent({ ...agent, status: value ? 1 : 0 }, true);
}}
/>
</span>
</div>
);
},
},
{
title: '更新人',
dataIndex: 'updatedBy',
key: 'updatedBy',
},
{
title: '更新时间',
dataIndex: 'updatedAt',
key: 'updatedAt',
render: (value: string) => {
return moment(value).format('YYYY-MM-DD HH:mm:ss');
},
},
{
title: '操作',
dataIndex: 'x',
key: 'x',
render: (_: any, agent: AgentType) => {
return (
<div className={styles.operateIcons}>
<a
onClick={() => {
onSelectAgent(agent);
}}
>
</a>
<Popconfirm
title="确定删除吗?"
onCancel={(e) => {
e?.stopPropagation();
}}
onConfirm={() => {
onDeleteAgent(agent.id!);
}}
>
<a></a>
</Popconfirm>
</div>
);
},
},
];
return (
<div className={styles.agentsSection}>
{/* <div className={styles.sectionTitle}>问答助理</div> */}
<div className={styles.content}>
<div className={styles.searchBar}>
{/* <Search
placeholder="请输入助理名称搜索"
className={styles.searchControl}
value={searchName}
onChange={(e) => {
setSearchName(e.target.value);
}}
onSearch={(value) => {
setShowAgents(
agents.filter((agent) =>
agent.name?.trim().toLowerCase().includes(value.trim().toLowerCase()),
),
);
}}
/> */}
<Button
type="primary"
onClick={() => {
@@ -61,81 +135,97 @@ const AgentsSection: React.FC<Props> = ({
<PlusOutlined />
</Button>
<div className={styles.switchShowType}>
<span className={styles.switchShowTypeLabel}></span>
<Switch
size="small"
checked={showType === 'card'}
onChange={(value) => {
const showTypeValue = value ? 'card' : 'list';
setShowType(showTypeValue);
localStorage.setItem('AGENT_SHOW_TYPE', showTypeValue);
}}
/>
</div>
</div>
<div className={styles.agentsContainer}>
{showAgents.map((agent) => {
const agentItemClass = classNames(styles.agentItem, {
[styles.agentActive]: agent.id === currentAgent?.id,
});
return (
<div
className={agentItemClass}
key={agent.id}
onClick={() => {
onSelectAgent(agent);
}}
>
<UserOutlined className={styles.agentIcon} />
<div className={styles.agentContent}>
<div className={styles.agentNameBar}>
<div className={styles.agentName}>{agent.name}</div>
<div className={styles.operateIcons}>
<EditOutlined
className={styles.operateIcon}
onClick={(e) => {
e.stopPropagation();
onEditAgent(agent);
}}
/>
<Popconfirm
title="确定删除吗?"
onCancel={(e) => {
e?.stopPropagation();
}}
onConfirm={(e) => {
e?.stopPropagation();
onDeleteAgent(agent.id!);
}}
>
<DeleteOutlined
{showType === 'list' ? (
<Table columns={columns} dataSource={showAgents} />
) : (
<div className={styles.agentsContainer}>
{showAgents.map((agent) => {
const agentItemClass = classNames(styles.agentItem, {
[styles.agentActive]: agent.id === currentAgent?.id,
});
return (
<div
className={agentItemClass}
key={agent.id}
onClick={() => {
onSelectAgent(agent);
}}
>
<UserOutlined className={styles.agentIcon} />
<div className={styles.agentContent}>
<div className={styles.agentNameBar}>
<div className={styles.agentName}>{agent.name}</div>
<div className={styles.operateIcons}>
<EditOutlined
className={styles.operateIcon}
onClick={(e) => {
e.stopPropagation();
onEditAgent(agent);
}}
/>
</Popconfirm>
</div>
</div>
<div className={styles.bottomBar}>
<div className={styles.agentDescription} title={agent.description}>
{agent.description}
</div>
<div className={styles.toggleStatus}>
{agent.status === 0 ? (
'已禁用'
) : (
<span className={styles.online}></span>
)}
<span
onClick={(e) => {
e.stopPropagation();
}}
>
<Switch
size="small"
defaultChecked={agent.status === 1}
onChange={(value) => {
onSaveAgent({ ...agent, status: value ? 1 : 0 }, true);
<Popconfirm
title="确定删除吗?"
onCancel={(e) => {
e?.stopPropagation();
}}
/>
</span>
onConfirm={(e) => {
e?.stopPropagation();
onDeleteAgent(agent.id!);
}}
>
<DeleteOutlined
className={styles.operateIcon}
onClick={(e) => {
e.stopPropagation();
}}
/>
</Popconfirm>
</div>
</div>
<div className={styles.bottomBar}>
<div className={styles.agentDescription} title={agent.description}>
{agent.description}
</div>
<div className={styles.toggleStatus}>
{agent.status === 0 ? (
'已禁用'
) : (
<span className={styles.online}></span>
)}
<span
onClick={(e) => {
e.stopPropagation();
}}
>
<Switch
size="small"
defaultChecked={agent.status === 1}
onChange={(value) => {
onSaveAgent({ ...agent, status: value ? 1 : 0 }, true);
}}
/>
</span>
</div>
</div>
</div>
</div>
</div>
);
})}
</div>
);
})}
</div>
)}
</div>
</div>
);

View File

@@ -1,5 +1,4 @@
.agent {
// background: #fff;
height: calc(100vh - 48px);
}
@@ -20,7 +19,7 @@
.searchBar {
display: flex;
align-items: center;
column-gap: 20px;
column-gap: 30px;
margin-bottom: 40px;
.searchControl {
@@ -290,3 +289,16 @@
}
}
}
.switchShowTypeLabel {
color: #999;
font-weight: 500;
font-size: 14px;
margin-right: 12px;
}
.operateIcons {
display: flex;
align-items: center;
column-gap: 12px;
}