diff --git a/src/ChatList/Item.tsx b/src/ChatList/Item.tsx index 0b28cbf8..717250e5 100644 --- a/src/ChatList/Item.tsx +++ b/src/ChatList/Item.tsx @@ -127,6 +127,7 @@ const Item = memo((props) => { if (renderMessagesExtra?.[item.role]) RenderFunction = renderMessagesExtra[item.role]; if (renderMessagesExtra?.['default']) RenderFunction = renderMessagesExtra['default']; if (!RenderFunction && !RenderFunction) return; + return ; }, [renderMessagesExtra?.[item.role]], diff --git a/src/ProChat/components/ChatList/Extras/Assistant.tsx b/src/ProChat/components/ChatList/Extras/Assistant.tsx index 1b1d5d55..98583db2 100644 --- a/src/ProChat/components/ChatList/Extras/Assistant.tsx +++ b/src/ProChat/components/ChatList/Extras/Assistant.tsx @@ -6,15 +6,19 @@ import { Flexbox } from 'react-layout-kit'; import { useStore } from '@/ProChat/store'; -export const AssistantMessageExtra: RenderMessageExtra = memo(({ extra }) => { - const model = useStore((s) => s.config.model); +export const AssistantMessageExtra: RenderMessageExtra = memo(({ extra, ...rest }) => { + const [model, messageItemExtraRender] = useStore((s) => [ + s.config.model, + s.messageItemExtraRender, + ]); const showModelTag = extra?.fromModel && model !== extra?.fromModel; const hasTranslate = !!extra?.translate; const showExtra = showModelTag || hasTranslate; - if (!showExtra) return; + const dom = messageItemExtraRender?.(rest, 'assistant'); + if (!showExtra && !dom) return; return ( @@ -24,6 +28,7 @@ export const AssistantMessageExtra: RenderMessageExtra = memo(({ extra }) => { {extra?.fromModel as string} )} + {dom} ); }); diff --git a/src/ProChat/components/ChatList/Extras/User.tsx b/src/ProChat/components/ChatList/Extras/User.tsx index fe5b84df..ad6c6978 100644 --- a/src/ProChat/components/ChatList/Extras/User.tsx +++ b/src/ProChat/components/ChatList/Extras/User.tsx @@ -3,9 +3,12 @@ import { Divider } from 'antd'; import { memo } from 'react'; import { Flexbox } from 'react-layout-kit'; -export const UserMessageExtra: RenderMessageExtra = memo(({ extra }) => { +import { useStore } from '@/ProChat/store'; + +export const UserMessageExtra: RenderMessageExtra = memo(({ extra, ...rest }) => { const hasTranslate = !!extra?.translate; + const [messageItemExtraRender] = useStore((s) => [s.messageItemExtraRender]); return ( {extra?.translate && ( @@ -13,6 +16,7 @@ export const UserMessageExtra: RenderMessageExtra = memo(({ extra }) => { )} + {messageItemExtraRender?.(rest, 'user')} ); }); diff --git a/src/ProChat/components/InputArea/AutoCompleteTextArea.tsx b/src/ProChat/components/InputArea/AutoCompleteTextArea.tsx new file mode 100644 index 00000000..2c869565 --- /dev/null +++ b/src/ProChat/components/InputArea/AutoCompleteTextArea.tsx @@ -0,0 +1,31 @@ +import { AutoComplete, Input } from 'antd'; +import { TextAreaProps } from 'antd/es/input'; +import { useState } from 'react'; +import { useStore } from '../../store'; + +export const AutoCompleteTextArea: React.FC = (props) => { + const [autocompleteRequest] = useStore((s) => [s.autocompleteRequest]); + + const [options, setOptions] = useState<{ value: string; label: string }[]>([]); + + return ( + { + props.onChange?.({ target: { value } } as any); + setOptions([]); + }} + onSearch={async (value) => { + const result = await autocompleteRequest?.(value); + setOptions((result as any[]) || []); + }} + > + + + ); +}; diff --git a/src/ProChat/components/InputArea/index.tsx b/src/ProChat/components/InputArea/index.tsx index e4ad3e3f..e32c27ed 100644 --- a/src/ProChat/components/InputArea/index.tsx +++ b/src/ProChat/components/InputArea/index.tsx @@ -1,5 +1,5 @@ import { SendOutlined } from '@ant-design/icons'; -import { Button, ConfigProvider, Input } from 'antd'; +import { Button, ConfigProvider } from 'antd'; import { createStyles, useResponsive } from 'antd-style'; import { memo, useRef, useState } from 'react'; import { Flexbox } from 'react-layout-kit'; @@ -7,6 +7,7 @@ import { Flexbox } from 'react-layout-kit'; import { useStore } from '../../store'; import ActionBar from './ActionBar'; +import { AutoCompleteTextArea } from './AutoCompleteTextArea'; const useStyles = createStyles(({ css, responsive, token }) => ({ container: css` @@ -30,13 +31,15 @@ const useStyles = createStyles(({ css, responsive, token }) => ({ `, input: css` width: 100%; + border: none; + outline: none; border-radius: 8px; `, btn: css` position: absolute; z-index: 10; right: 8px; - bottom: 8px; + bottom: 6px; color: ${token.colorTextTertiary}; &:hover { @@ -49,10 +52,13 @@ const useStyles = createStyles(({ css, responsive, token }) => ({ })); export const InputArea = ({}) => { - const [sendMessage, isLoading] = useStore((s) => [s.sendMessage, !!s.chatLoadingId]); + const [sendMessage, isLoading, placeholder] = useStore((s) => [ + s.sendMessage, + !!s.chatLoadingId, + s.placeholder, + ]); const [message, setMessage] = useState(''); const isChineseInput = useRef(false); - const { styles, theme } = useStyles(); const { mobile } = useResponsive(); @@ -76,10 +82,10 @@ export const InputArea = ({}) => { - { setMessage(e.target.value); }} diff --git a/src/ProChat/container/index.tsx b/src/ProChat/container/index.tsx index 24008d50..b33579d5 100644 --- a/src/ProChat/container/index.tsx +++ b/src/ProChat/container/index.tsx @@ -32,6 +32,7 @@ export const ProChat = memo( onResetMessage, style, className, + autocompleteRequest, ...props }) => { return ( @@ -44,6 +45,7 @@ export const ProChat = memo( assistantMeta={assistantMeta} request={request} onResetMessage={onResetMessage} + autocompleteRequest={autocompleteRequest} {...props} devtoolOptions={__PRO_CHAT_STORE_DEVTOOLS__} > diff --git a/src/ProChat/demos/default.tsx b/src/ProChat/demos/default.tsx index c42c867f..f849e8b5 100644 --- a/src/ProChat/demos/default.tsx +++ b/src/ProChat/demos/default.tsx @@ -13,6 +13,17 @@ export default () => { { + if (value === '/') { + return [{ value: '你可以帮助我列出问题吗?', label: '你可以帮助我列出问题吗?' }]; + } + return []; + }} + messageItemExtraRender={(_, type) => { + if (type === 'user') return 🦐; + return 👍; + }} + placeholder="输入 / 查看推荐问题,或者直接输入你的问题" onResetMessage={async () => { console.log('数据清空'); }} diff --git a/src/ProChat/store/initialState.ts b/src/ProChat/store/initialState.ts index 253658e1..684a9299 100644 --- a/src/ProChat/store/initialState.ts +++ b/src/ProChat/store/initialState.ts @@ -29,6 +29,30 @@ export interface ChatPropsState { * @returns */ onResetMessage?: () => Promise; + + /** + * 获取自动完成列表的 request + * @param value + * @returns + */ + autocompleteRequest?: (value: string) => Promise< + { + value: string; + label?: string; + }[] + >; + + /** + * 输入框的 placeholder + */ + placeholder?: string; + + /** + * 信息框额外渲染 + */ + messageItemExtraRender?: (message: ChatMessage, type: 'assistant' | 'user') => React.ReactNode; + + /** */ // /** // * 控制是否流式输出 // * @default true