[feature](webapp) add mobile agents drawer (#64)

This commit is contained in:
williamhliu
2023-09-10 11:50:26 +08:00
committed by GitHub
parent 5bab18e092
commit 3c0edb67c7
13 changed files with 171 additions and 26 deletions

View File

@@ -192,6 +192,6 @@
]
},
"engines": {
"node": ">=14.18.0"
"node": ">=16"
}
}

View File

@@ -248,6 +248,8 @@
&-entity-info {
display: flex;
align-items: center;
flex-wrap: wrap;
row-gap: 6px;
column-gap: 12px;
margin-top: 4px;
color: var(--text-color-third);
@@ -257,6 +259,8 @@
&-dimension-item {
display: flex;
align-items: center;
flex-wrap: wrap;
row-gap: 6px;
}
&-dimension-name {

View File

@@ -34,7 +34,7 @@ const ROUTES = [
component: './Agent',
envEnableList: [ENV_KEY.CHAT],
},
{
{
path: '/model',
name: 'semanticModel',
envEnableList: [ENV_KEY.SEMANTIC],
@@ -53,7 +53,6 @@ const ROUTES = [
},
],
},
{
path: '/database',
name: 'database',

View File

@@ -98,7 +98,7 @@
"react-split-pane": "^2.0.3",
"react-syntax-highlighter": "^15.4.3",
"sql-formatter": "^2.3.3",
"supersonic-chat-sdk": "^0.5.29",
"supersonic-chat-sdk": "0.0.0",
"umi": "3.5",
"umi-request": "^1.0.8"
},
@@ -147,4 +147,4 @@
"@types/react": "17.0.0"
},
"__npminstall_done": false
}
}

View File

@@ -4,20 +4,7 @@ import styles from './style.less';
import classNames from 'classnames';
import { message } from 'antd';
import IconFont from '@/components/IconFont';
const agents = [
'icon-fukuanbaobiaochaxun',
'icon-hangweifenxi1',
'icon-xiaofeifenxi',
'icon-renwuchaxun',
'icon-liushuichaxun',
'icon-baobiao',
'icon-cangkuchaxun',
'icon-xiaoshoushuju',
'icon-tongji',
'icon-shujutongji',
'icon-mendiankanban',
];
import { AGENT_ICONS } from '../constants';
type Props = {
agentList: AgentType[];
@@ -49,8 +36,7 @@ const AgentList: React.FC<Props> = ({ agentList, currentAgent, onSelectAgent })
onSelectAgent(agent);
}}
>
{/* <img src={agents[index % agents.length]} alt="avatar" className={styles.avatar} /> */}
<IconFont type={agents[index % agents.length]} className={styles.avatar} />
<IconFont type={AGENT_ICONS[index % AGENT_ICONS.length]} className={styles.avatar} />
<div className={styles.agentInfo}>
<div className={styles.agentName}>{agent.name}</div>
<div className={styles.agentDesc}>{agent.description}</div>

View File

@@ -66,10 +66,12 @@
}
}
&:hover, &.active {
&:hover,
&.active {
background: #22a5f7;
.agentName, .agentDesc {
.agentName,
.agentDesc {
color: #fff;
}
}

View File

@@ -16,6 +16,7 @@ type Props = {
currentAgent?: AgentType;
agentList: AgentType[];
onToggleHistoryVisible: () => void;
onOpenMobileAgents: () => void;
onInputMsgChange: (value: string) => void;
onSendMsg: (msg: string, modelId?: number) => void;
onAddConversation: (agent?: AgentType) => void;
@@ -41,6 +42,7 @@ const ChatFooter: ForwardRefRenderFunction<any, Props> = (
currentAgent,
agentList,
onToggleHistoryVisible,
onOpenMobileAgents,
onInputMsgChange,
onSendMsg,
onAddConversation,
@@ -310,6 +312,12 @@ const ChatFooter: ForwardRefRenderFunction<any, Props> = (
<div></div>
</div>
)}
{isMobile && (
<div className={styles.toolItem} onClick={onOpenMobileAgents}>
<IconFont type="icon-zhinengzhuli" className={styles.toolIcon} />
<div></div>
</div>
)}
</div>
<div className={styles.composer}>
<div className={styles.composerInputWrapper}>

View File

@@ -0,0 +1,62 @@
import IconFont from '@/components/IconFont';
import { Drawer } from 'antd';
import classNames from 'classnames';
import { AGENT_ICONS } from '../constants';
import { AgentType } from '../type';
import styles from './style.less';
type Props = {
open: boolean;
agentList: AgentType[];
currentAgent?: AgentType;
onSelectAgent: (agent: AgentType) => void;
onClose: () => void;
};
const MobileAgents: React.FC<Props> = ({
open,
agentList,
currentAgent,
onSelectAgent,
onClose,
}) => {
return (
<Drawer
title="智能助理"
placement="bottom"
open={open}
height="85%"
className={styles.mobileAgents}
onClose={onClose}
>
<div className={styles.agentListContent}>
{agentList.map((agent, index) => {
const agentItemClass = classNames(styles.agentItem, {
[styles.active]: currentAgent?.id === agent.id,
});
return (
<div
key={agent.id}
className={agentItemClass}
onClick={() => {
onSelectAgent(agent);
onClose();
}}
>
<div className={styles.agentTitleBar}>
<IconFont
type={AGENT_ICONS[index % AGENT_ICONS.length]}
className={styles.avatar}
/>
<div className={styles.agentName}>{agent.name}</div>
</div>
<div className={styles.agentDesc}>{agent.description}</div>
</div>
);
})}
</div>
</Drawer>
);
};
export default MobileAgents;

View File

@@ -0,0 +1,55 @@
.mobileAgents {
:global {
.ant-drawer-content {
border-top-left-radius: 12px;
border-top-right-radius: 12px;
.ant-drawer-header {
padding: 16px 12px;
}
.ant-drawer-body {
padding: 12px;
}
}
}
.agentListContent {
display: flex;
flex-direction: column;
row-gap: 12px;
.agentItem {
padding: 12px 16px;
background-color: #f5f7f9;
border: 1px solid transparent;
border-radius: 10px;
&.active {
border: 1px solid var(--chat-blue);
}
.agentTitleBar {
display: flex;
align-items: center;
column-gap: 6px;
.avatar {
font-size: 24px;
}
.agentName {
color: var(--text-color);
font-weight: 500;
}
}
.agentDesc {
margin-top: 8px;
color: var(--text-color-third);
font-size: 13px;
line-height: 24px;
}
}
}
}

View File

@@ -27,6 +27,20 @@ export const SEMANTIC_TYPE_MAP = {
[SemanticTypeEnum.VALUE]: '维度值',
};
export const AGENT_ICONS = [
'icon-fukuanbaobiaochaxun',
'icon-hangweifenxi1',
'icon-xiaofeifenxi',
'icon-renwuchaxun',
'icon-baobiao',
'icon-liushuichaxun',
'icon-cangkuchaxun',
'icon-xiaoshoushuju',
'icon-tongji',
'icon-shujutongji',
'icon-mendiankanban',
];
export const CHAT_TITLE = '';
export const DEFAULT_CONVERSATION_NAME = '新问答对话';

View File

@@ -23,6 +23,7 @@ import 'supersonic-chat-sdk/dist/index.css';
import { setToken as setChatSdkToken } from 'supersonic-chat-sdk';
import AgentList from './AgentList';
import { AUTH_TOKEN_KEY } from '@/common/constants';
import MobileAgents from './MobileAgents';
type Props = {
isCopilotMode?: boolean;
@@ -58,6 +59,7 @@ const Chat: React.FC<Props> = ({
const [defaultEntity, setDefaultEntity] = useState<DefaultEntityType>();
const [agentList, setAgentList] = useState<AgentType[]>([]);
const [currentAgent, setCurrentAgent] = useState<AgentType>();
const [mobileAgentsVisible, setMobileAgentsVisible] = useState(false);
const dispatch = useDispatch();
const conversationRef = useRef<any>();
@@ -403,6 +405,9 @@ const Chat: React.FC<Props> = ({
onSendMsg={sendMsg}
onAddConversation={onAddConversation}
onSelectAgent={onSelectAgent}
onOpenMobileAgents={() => {
setMobileAgentsVisible(true);
}}
ref={chatFooterRef}
/>
</div>
@@ -423,6 +428,15 @@ const Chat: React.FC<Props> = ({
ref={conversationRef}
/>
</div>
<MobileAgents
open={mobileAgentsVisible}
agentList={agentList}
currentAgent={currentAgent}
onSelectAgent={onSelectAgent}
onClose={() => {
setMobileAgentsVisible(false);
}}
/>
</div>
);
};

View File

@@ -243,7 +243,7 @@ const DetailModal: React.FC<Props> = ({ detail, onSubmit, onCancel }) => {
<FormItem name="pattern" label="函数描述">
<TextArea placeholder="请输入函数描述,多个描述换行分隔" allowClear />
</FormItem>
<FormItem name="params" label="函数参数" hidden={pluginType === PluginTypeEnum.DSL}>
{/* <FormItem name="params" label="函数参数" hidden={pluginType === PluginTypeEnum.DSL}>
<div className={styles.paramsSection}>
{functionParams.map((functionParam: FunctionParamFormItemType) => {
const { id, name, type, description } = functionParam;
@@ -300,7 +300,7 @@ const DetailModal: React.FC<Props> = ({ detail, onSubmit, onCancel }) => {
新增函数参数
</Button>
</div>
</FormItem>
</FormItem> */}
<FormItem name="exampleQuestions" label="示例问题">
<div className={styles.paramsSection}>
{examples.map((example) => {
@@ -340,7 +340,7 @@ const DetailModal: React.FC<Props> = ({ detail, onSubmit, onCancel }) => {
<FormItem name="url" label="地址" rules={[{ required: true, message: '请输入地址' }]}>
<Input placeholder="请输入地址" allowClear />
</FormItem>
<FormItem name="params" label="参数">
<FormItem name="params" label="函数参数">
<div className={styles.paramsSection}>
{filters.map((filter: any) => {
return (

View File

@@ -16,6 +16,7 @@
"allowJs": true,
"skipLibCheck": true,
"experimentalDecorators": true,
"suppressImplicitAnyIndexErrors": true,
"ignoreDeprecations": "5.0",
"strict": true,
"paths": {