diff --git a/shared/contexts/ChatBoxContext.tsx b/shared/contexts/ChatBoxContext.tsx index 8bbb1c9e..a5403734 100644 --- a/shared/contexts/ChatBoxContext.tsx +++ b/shared/contexts/ChatBoxContext.tsx @@ -1,6 +1,6 @@ import React, { useCallback, useContext, useState } from 'react'; import _noop from 'lodash/noop'; -import type { ReplyMsgType } from '../utils/msg-helper'; +import type { ReplyMsgType } from '../utils/message-helper'; /** * 一个消息盒的上下文 diff --git a/shared/model/message.ts b/shared/model/message.ts index 2b3f76b8..4f7c89e8 100644 --- a/shared/model/message.ts +++ b/shared/model/message.ts @@ -13,17 +13,23 @@ export interface ChatMessage { reactions?: any[]; + meta?: Record; + createdAt?: string; updatedAt?: string; } -export interface SendMessagePayload { +export interface SimpleMessagePayload { groupId?: string; converseId: string; content: string; } +export interface SendMessagePayload extends SimpleMessagePayload { + meta?: Record; +} + /** * 获取会话消息 * @param converseId 会话ID diff --git a/shared/redux/hooks/useConverseMessage.ts b/shared/redux/hooks/useConverseMessage.ts index 149f4804..7c7f1f5a 100644 --- a/shared/redux/hooks/useConverseMessage.ts +++ b/shared/redux/hooks/useConverseMessage.ts @@ -10,6 +10,49 @@ import { import { chatActions } from '../slices'; import { useAppDispatch, useAppSelector } from './useAppSelector'; import _isNil from 'lodash/isNil'; +import { useChatBoxContext } from '../..'; +import { MessageHelper } from '../../utils/message-helper'; + +function useHandleSendMessage(context: ConverseContext) { + const { converseId } = context; + const dispatch = useAppDispatch(); + const { hasContext, replyMsg, clearReplyMsg } = useChatBoxContext(); + + /** + * 发送消息 + */ + const handleSendMessage = useCallback( + async (payload: SendMessagePayload) => { + try { + if (hasContext === true) { + // 如果有上下文, 则组装payload + const msgHelper = new MessageHelper(payload); + if (!_isNil(replyMsg)) { + msgHelper.setReplyMsg(replyMsg); + clearReplyMsg(); + } + + payload = msgHelper.generatePayload(); + } + + // TODO: 增加临时消息, 对网络环境不佳的状态进行优化 + + const message = await sendMessage(payload); + dispatch( + chatActions.appendConverseMessage({ + converseId, + messages: [message], + }) + ); + } catch (err) { + showErrorToasts(err); + } + }, + [converseId, hasContext, replyMsg, clearReplyMsg] + ); + + return handleSendMessage; +} /** * 会话消息管理 @@ -81,21 +124,7 @@ export function useConverseMessage(context: ConverseContext) { } }, [converseId]); - const handleSendMessage = useCallback(async (payload: SendMessagePayload) => { - // TODO: 增加临时消息, 对网络环境不佳的状态进行优化 - - try { - const message = await sendMessage(payload); - dispatch( - chatActions.appendConverseMessage({ - converseId, - messages: [message], - }) - ); - } catch (err) { - showErrorToasts(err); - } - }, []); + const handleSendMessage = useHandleSendMessage(context); return { messages, loading, error, handleSendMessage }; } diff --git a/shared/utils/message-helper.ts b/shared/utils/message-helper.ts new file mode 100644 index 00000000..5e3f1e31 --- /dev/null +++ b/shared/utils/message-helper.ts @@ -0,0 +1,34 @@ +import type { + ChatMessage, + SendMessagePayload, + SimpleMessagePayload, +} from '../model/message'; +import _isNil from 'lodash/isNil'; +import _set from 'lodash/set'; +import _pick from 'lodash/pick'; + +const replyMsgFields = ['_id', 'content', 'author'] as const; +export type ReplyMsgType = Pick; + +export class MessageHelper { + private payload: SendMessagePayload; + + constructor(origin: SimpleMessagePayload) { + this.payload = { ...origin }; + } + + setReplyMsg(replyMsg: ReplyMsgType) { + if (_isNil(replyMsg)) { + return; + } + + _set(this.payload, ['meta', 'reply'], _pick(replyMsg, replyMsgFields)); + } + + /** + * 生成待发送的消息体 + */ + generatePayload(): SendMessagePayload { + return { ...this.payload }; + } +} diff --git a/shared/utils/msg-helper.ts b/shared/utils/msg-helper.ts deleted file mode 100644 index 6aba24f6..00000000 --- a/shared/utils/msg-helper.ts +++ /dev/null @@ -1,4 +0,0 @@ -import type { ChatMessage } from '../model/message'; - -const replyMsgFields = ['_id', 'content', 'author'] as const; -export type ReplyMsgType = Pick; diff --git a/web/src/components/ChatBox/ChatInputBox/index.tsx b/web/src/components/ChatBox/ChatInputBox/index.tsx index 9b31ff07..c5fc2625 100644 --- a/web/src/components/ChatBox/ChatInputBox/index.tsx +++ b/web/src/components/ChatBox/ChatInputBox/index.tsx @@ -46,7 +46,7 @@ export const ChatInputBox: React.FC = React.memo((props) => { const fileInfo = await uploadFile(image); const imageRemoteUrl = fileInfo.url; - // TODO: not good + // TODO: not good, should bind with plugin bbcode props.onSendMsg(`[img]${imageRemoteUrl}[/img]`); closeModal(key); }} diff --git a/web/src/components/ChatBox/index.tsx b/web/src/components/ChatBox/index.tsx index 7dd784dc..c1383bc0 100644 --- a/web/src/components/ChatBox/index.tsx +++ b/web/src/components/ChatBox/index.tsx @@ -18,7 +18,7 @@ type ChatBoxProps = isGroup: true; groupId: string; }; -export const ChatBox: React.FC = React.memo((props) => { +const ChatBoxInner: React.FC = React.memo((props) => { const { converseId, isGroup } = props; const { messages, loading, error, handleSendMessage } = useConverseMessage({ converseId, @@ -36,29 +36,36 @@ export const ChatBox: React.FC = React.memo((props) => { } return ( - -
- +
+ - + + + { + // 发送消息后滚动到底部 + handleSendMessage({ + converseId: props.converseId, + groupId: props.groupId, + content: msg, + }).then(() => { + chatMessageListRef.current?.scrollToBottom(); + }); + }} + /> +
+ ); +}); +ChatBoxInner.displayName = 'ChatBoxInner'; - { - // 发送消息后滚动到底部 - handleSendMessage({ - converseId: props.converseId, - groupId: props.groupId, - content: msg, - }).then(() => { - chatMessageListRef.current?.scrollToBottom(); - }); - }} - /> -
+export const ChatBox: React.FC = React.memo((props) => { + return ( + + ); });