From bf5b36832c6632a1d4f75e991a66fa3b5cc50495 Mon Sep 17 00:00:00 2001 From: Lei OT Date: Fri, 15 Mar 2024 18:40:34 +0800 Subject: [PATCH] =?UTF-8?q?perf:=20=E5=8E=86=E5=8F=B2=E8=AE=B0=E5=BD=95?= =?UTF-8?q?=E7=9A=84=E6=AF=8F=E9=A1=B5=E5=8A=A0=E8=BD=BD,=205000;=20=0Bfix?= =?UTF-8?q?:=20=E5=A4=84=E7=90=86=E5=BD=93=E5=89=8D=E5=AE=A2=E6=88=B7?= =?UTF-8?q?=E7=AB=AF=E6=94=B6=E5=88=B0=E6=96=B0=E4=BC=9A=E8=AF=9D.=20?= =?UTF-8?q?=E5=8C=85=E6=8B=AC=E5=8F=91=E5=87=BA=E7=9A=84;?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit fix: 消息数重复累计 websocket 连接重复初始化 --- src/components/SearchInput.jsx | 2 +- src/lib/msgUtils.js | 4 +- src/stores/ConversationStore.js | 45 ++++++++++++++++--- src/views/AuthApp.jsx | 33 +++++--------- src/views/ChatHistory.jsx | 19 +++++--- .../Conversations/Components/MessagesList.jsx | 10 ++++- src/views/Conversations/Conversations.css | 25 +++++++++++ 7 files changed, 99 insertions(+), 39 deletions(-) diff --git a/src/components/SearchInput.jsx b/src/components/SearchInput.jsx index cfd7354..58feb91 100644 --- a/src/components/SearchInput.jsx +++ b/src/components/SearchInput.jsx @@ -29,8 +29,8 @@ function DebounceSelect({ fetchOptions, debounceTimeout = 800, ...props }) { filterOption={false} showSearch allowClear - {...props} maxTagCount={1} + {...props} onSearch={debounceFetcher} notFoundContent={fetching ? : null} optionFilterProp='label' diff --git a/src/lib/msgUtils.js b/src/lib/msgUtils.js index 38b57cf..02265c2 100644 --- a/src/lib/msgUtils.js +++ b/src/lib/msgUtils.js @@ -235,6 +235,8 @@ export const receivedMsgTypeMapped = { id: msgcontent.wamid, status: msgStatusRenderMapped[(msgcontent?.status || 'failed')], conversationid: msgcontent.actionId.split('.')[0], // msgcontent.conversation.sn, + date: msgcontent.createTime, + sender: 'me', }), }, 'error': { @@ -384,7 +386,7 @@ export const whatsappMsgTypeMapped = { }), renderForReply: (msg) => ({ id: msg.wamid, - message: '[联系人]', + message: '[联系人] ' + msg.contacts[0].name.formatted_name + '...', }), }, location: { diff --git a/src/stores/ConversationStore.js b/src/stores/ConversationStore.js index 8d13508..6a52695 100644 --- a/src/stores/ConversationStore.js +++ b/src/stores/ConversationStore.js @@ -8,6 +8,18 @@ import { WS_URL } from '@/config'; // const WS_URL = 'ws://202.103.68.144:8888/whatever/'; // const WS_URL = 'ws://120.79.9.217:10022/whatever/'; +const conversationRow = { + sn: '', + opi_sn: '', + coli_sn: '', + coli_id: '', + last_received_time: '', + last_send_time: '', + unread_msg_count: '', + whatsapp_name: '', + customer_name: '', + whatsapp_phone_number: '', +}; const initialConversationState = { // websocket: null, @@ -217,7 +229,7 @@ const messageSlice = (set, get) => ({ // msgUpdate console.log('UPDATE_SENT_MESSAGE_ITEM-----------------------------------------------------------------'); // 更新会话中的消息 - const { activeConversations, conversationsList } = get(); + const { activeConversations, conversationsList, currentConversation } = get(); const targetId = message.conversationid; const targetMsgs = (activeConversations[String(targetId)] || []).map((ele) => { // 更新状态 @@ -236,18 +248,32 @@ const messageSlice = (set, get) => ({ targetMsgs.push(message); } - // 更新列表的时间 - if (message.status === 'received') { // 'delivered' - const targetIndex = conversationsList.findIndex((ele) => String(ele.sn) === String(targetId)); + const targetIndex = conversationsList.findIndex((ele) => String(ele.sn) === String(targetId)); + let newConversations = []; + if (targetIndex !== -1 && message.status === 'received') { // 'delivered' + // 更新列表的时间 conversationsList.splice(targetIndex, 1, { ...conversationsList[targetIndex], last_received_time: message.deliverTime, // todo: 需要+8 hours }); + } else if (targetIndex === -1) { + // 当前客户端不存在的会话 todo: 设置为当前(在WhatsApp返回号码不一致时) + newConversations = [{ + ...conversationRow, + ...message, + sn: targetId, + opi_sn: currentConversation.opi_sn, // todo: coli sn + last_received_time: message.date, + unread_msg_count: 0, + whatsapp_name: message?.senderName || message?.sender || '', + customer_name: message?.senderName || message?.sender || '', + whatsapp_phone_number: message.from, + }]; } return set({ activeConversations: { ...activeConversations, [String(targetId)]: targetMsgs }, - conversationsList: [...conversationsList], + conversationsList: [...newConversations, ...conversationsList], }); }, sentOrReceivedNewMessage: (targetId, message) => { @@ -257,7 +283,7 @@ const messageSlice = (set, get) => ({ const targetIndex = conversationsList.findIndex((ele) => String(ele.sn) === String(targetId)); const lastReceivedTime = message.type !== 'system' && message.sender !== 'me' ? message.date : null; const newConversation = - targetId !== -1 + targetIndex !== -1 ? { ...conversationsList[targetIndex], last_received_time: lastReceivedTime || conversationsList[targetIndex].last_received_time, @@ -267,15 +293,20 @@ const messageSlice = (set, get) => ({ : conversationsList[targetIndex].unread_msg_count, } : { + ...conversationRow, ...message, sn: targetId, + opi_sn: currentConversation.opi_sn, // todo: coli sn last_received_time: message.date, unread_msg_count: message.sender === 'me' ? 0 : 1, + whatsapp_name: message?.senderName || message?.sender || '', + customer_name: message?.senderName || message?.sender || '', + whatsapp_phone_number: message.from, }; conversationsList.splice(targetIndex, 1); conversationsList.unshift(newConversation); return set({ - totalNotify: totalNotify + newConversation.unread_msg_count, + totalNotify: totalNotify + (message.sender === 'me' ? 0 : 1), activeConversations: { ...activeConversations, [String(targetId)]: [...targetMsgs, message] }, conversationsList: [...conversationsList], currentConversation: { diff --git a/src/views/AuthApp.jsx b/src/views/AuthApp.jsx index 3a01cea..5adfc21 100644 --- a/src/views/AuthApp.jsx +++ b/src/views/AuthApp.jsx @@ -19,15 +19,21 @@ function AuthApp() { const loginUser = useAuthStore(state => state.loginUser) const href = useHref() - + + const [connectWebsocket, fetchInitialData, disconnectWebsocket ] = useConversationStore((state) => [ + state.connectWebsocket, + state.fetchInitialData, + state.disconnectWebsocket, + ]); useEffect(() => { + Notification.requestPermission(); if (loginUser.userId > 0) { - useConversationStore.getState().connectWebsocket(loginUser.userId) - useConversationStore.getState().fetchInitialData(loginUser.userId) // userIdStr + connectWebsocket(loginUser.userId); + fetchInitialData(loginUser.userId); // userIdStr } return () => { - useConversationStore.getState().disconnectWebsocket(); - } + disconnectWebsocket(); + }; }, []) useEffect(() => { @@ -37,21 +43,6 @@ function AuthApp() { } }, [href]) - useEffect(() => { - if (loginUser.userId > 0) { - useConversationStore.getState().connectWebsocket(loginUser.userId) - useConversationStore.getState().fetchInitialData(loginUser.userId) // userIdStr - } - return () => { - useConversationStore.getState().disconnectWebsocket() - } - }, []) - - useEffect(() => { - Notification.requestPermission() - return () => {} - }, []) - const { token: { colorBgContainer }, } = theme.useToken() @@ -69,7 +60,7 @@ function AuthApp() { renderEmpty={() => } > - + diff --git a/src/views/ChatHistory.jsx b/src/views/ChatHistory.jsx index 1882e14..21779a2 100644 --- a/src/views/ChatHistory.jsx +++ b/src/views/ChatHistory.jsx @@ -14,6 +14,8 @@ const { Sider, Content, Header, Footer } = Layout; const { Search } = Input; const { RangePicker } = DatePicker; +const BIG_PAGE_SIZE = MESSAGE_PAGE_SIZE * 100; + // https://media-xsp2-1.cdn.whatsapp.net/v/t61.24694-24/424735646_380563021285029_2962758854250800176_n.jpg?ccb=11-4&oh=01_AdTogiVdUE-ToI9uH-VQKTTLyDbP7bocXUQe1OETOeCgcg&oe=65F7C6AB&_nc_sid=e6ed6c&_nc_cat=104 // eslint-disable-next-line react/display-name @@ -40,10 +42,10 @@ const SearchForm = memo(function ({ initialValues, onSubmit }) { onFinish={handleSubmit} style={{}}> - + - + @@ -103,18 +105,18 @@ function ChatHistory() { const getMessagesPre = async (chatItem) => { setMessageListPreLoading(true); - const data = await fetchMessagesHistory({ ...chatItem, lasttime: chatItem.pretime, pagedir: 'pre', }); + const data = await fetchMessagesHistory({ ...chatItem, lasttime: chatItem.pretime, pagedir: 'pre', pagesize: BIG_PAGE_SIZE }); setMessageListPreLoading(false); setChatItemMessages(prevValue => data.concat(prevValue)); - const loadPrePage = !(data.length === 0 || data.length < MESSAGE_PAGE_SIZE); + const loadPrePage = !(data.length === 0 || data.length < BIG_PAGE_SIZE); setParamsForMsgList({ loadPrePage }); }; const getMessagesNext = async (chatItem) => { setMessageListLoading(true); - const data = await fetchMessagesHistory({...chatItem, pagedir: 'next', }); + const data = await fetchMessagesHistory({...chatItem, pagedir: 'next', pagesize: BIG_PAGE_SIZE }); setMessageListLoading(false); setChatItemMessages(prevValue => prevValue.concat(data)); - const loadNextPage = !(data.length === 0 || data.length < MESSAGE_PAGE_SIZE); + const loadNextPage = !(data.length === 0 || data.length < BIG_PAGE_SIZE); setParamsForMsgList({loadNextPage}); }; @@ -129,7 +131,7 @@ function ChatHistory() { const findIndex = chatItemMessages.findIndex(item => item.id === selected.id); if (findIndex === -1) { setMessageListLoading(true); - await getMessagesPre({...paramsForMsgList, pagesize: 10000 }); + await getMessagesPre({...paramsForMsgList }); setMessageListLoading(false); } setSelectedMatch(selected); @@ -253,10 +255,12 @@ function ChatHistory() { const messagesEndRef = useRef(null); const messageRefs = useRef([]); + const [focusMsg, setFocusMsg] = useState(''); const scrollToMessage = (id, index) => { const _i = index || chatItemMessages.findIndex((msg) => msg.id === id); if (_i >= 0) { messageRefs.current[_i].scrollIntoView({ behavior: 'smooth', block: 'start' }); + setFocusMsg(id); } }; // eslint-disable-next-line react/display-name @@ -338,6 +342,7 @@ function ChatHistory() { 'whitespace-pre-wrap mb-2', message.whatsapp_msg_type === 'sticker' ? 'bg-transparent' : '', message.sender === 'me' ? 'whatsappme-container' : '', + focusMsg === message.id ? 'message-box-focus' : '', ].join(' ')} style={{ backgroundColor: message.sender === 'me' ? '#ccd4ae' : '#fff', diff --git a/src/views/Conversations/Components/MessagesList.jsx b/src/views/Conversations/Components/MessagesList.jsx index cac27f0..a93497b 100644 --- a/src/views/Conversations/Components/MessagesList.jsx +++ b/src/views/Conversations/Components/MessagesList.jsx @@ -11,6 +11,7 @@ const MessagesList = ({ messages, handlePreview, reference, longListLoading, get // const messagesEndRef = useRef(null); const messageRefs = useRef([]); + const [focusMsg, setFocusMsg] = useState(''); const scrollToBottom = (force = false) => { if (reference.current && (shouldScrollBottom || force)) { @@ -22,6 +23,7 @@ const MessagesList = ({ messages, handlePreview, reference, longListLoading, get const _i = index || messages.findIndex((msg) => msg.id === id); if (_i >= 0) { messageRefs.current[_i].scrollIntoView({ behavior: 'smooth', block: 'start' }); + setFocusMsg(id); } }; @@ -100,12 +102,16 @@ const MessagesList = ({ messages, handlePreview, reference, longListLoading, get styles: { backgroundColor: '#ccd4ae' }, notchStyle: { fill: '#ccd4ae' }, replyButton: ['text', 'document', 'image'].includes(message.whatsapp_msg_type) && message.status !== 'failed' ? true : false, - className: 'whatsappme-container whitespace-pre-wrap', } : { replyButton: ['text', 'document', 'image'].includes(message.whatsapp_msg_type) ? true : false, - className: ['whitespace-pre-wrap', message.whatsapp_msg_type === 'sticker' ? 'bg-transparent' : ''].join(' '), })} + className={[ + 'whitespace-pre-wrap', + message.whatsapp_msg_type === 'sticker' ? 'bg-transparent' : '', + message.sender === 'me' ? 'whatsappme-container' : '', + focusMsg === message.id ? 'message-box-focus' : '', + ].join(' ')} {...(message.type === 'meetingLink' ? { actionButtons: [ diff --git a/src/views/Conversations/Conversations.css b/src/views/Conversations/Conversations.css index 7b9b201..5b312be 100644 --- a/src/views/Conversations/Conversations.css +++ b/src/views/Conversations/Conversations.css @@ -184,3 +184,28 @@ -webkit-user-select: auto; -moz-user-select: auto; }*/ + +@-webkit-keyframes message-box-default-focus-x { + from { + background-color: #fff; + } + to { + background-color: #ece5dd; + } +} +@keyframes message-box-default-focus-x { + from { + background-color: #fff; + } + to { + background-color: #ece5dd; + } +} + +.chatwindow-wrapper .message-box-focus { + animation-iteration-count: 2; + -webkit-animation-iteration-count: 2; + -webkit-animation-duration: 1s; + animation-name: message-box-default-focus-x; + animation-duration: 1s; +}