在线窗口: 加载更多消息

dev/chat
Lei OT 2 years ago
parent 413e3381d8
commit 313e3f8478

@ -36,15 +36,9 @@ export const fetchMessages = async (params) => {
pagesize: MESSAGE_PAGE_SIZE, pagesize: MESSAGE_PAGE_SIZE,
}; };
const { errcode, result } = await fetchJSON(`${API_HOST}/getcusmessages`, {...defaultParams, ...params}); const { errcode, result } = await fetchJSON(`${API_HOST}/getcusmessages`, {...defaultParams, ...params});
return errcode !== 0 ? [] : parseRenderMessageList(result || []); return errcode !== 0 ? [] : parseRenderMessageList(result.reverse() || []);
} }
export const fetchCustomerProfile = async (colisn) => {
const { result } = await fetchJSON(`${API_HOST}/getorderinfo`, { colisn });
const data = result?.[0] || {};
return data;
};
/** /**
* *
* @param {object} params { opisn, whatsappid, colisn } * @param {object} params { opisn, whatsappid, colisn }
@ -72,3 +66,8 @@ export const fetchCleanUnreadMsgCount = async (params) => {
const { errcode, result } = await fetchJSON(`${API_HOST}/clean_unread_msg_count`, params); const { errcode, result } = await fetchJSON(`${API_HOST}/clean_unread_msg_count`, params);
return errcode !== 0 ? {} : result; return errcode !== 0 ? {} : result;
}; };
/**
* ------------------------------------------------------------------------------------------------
* 历史记录
*/

@ -149,7 +149,7 @@ const conversationSlice = (set, get) => ({
const newConversationsMapped = newConversations.reduce((r, v) => ({ ...r, [`${v.sn}`]: [] }), {}); const newConversationsMapped = newConversations.reduce((r, v) => ({ ...r, [`${v.sn}`]: [] }), {});
const newListIds = newList.map((chatItem) => `${chatItem.sn}`); const newListIds = newList.map((chatItem) => `${chatItem.sn}`);
const withoutNew = conversationsList.filter(item => !newListIds.includes(`${item.sn}`)); const withoutNew = conversationsList.filter((item) => !newListIds.includes(`${item.sn}`));
return set((state) => ({ return set((state) => ({
conversationsList: [...newList, ...withoutNew], conversationsList: [...newList, ...withoutNew],
@ -188,6 +188,7 @@ const conversationSlice = (set, get) => ({
conversationsList: [...conversationsList], conversationsList: [...conversationsList],
})); }));
}, },
updateCurrentConversation: (conversation) => set((state) => ({ currentConversation: { ...state.currentConversation, ...conversation } })),
updateConversationItem: (conversation) => { updateConversationItem: (conversation) => {
const { conversationsList } = get(); const { conversationsList } = get();
const targetId = conversation.sn; const targetId = conversation.sn;

@ -194,7 +194,7 @@ function ChatHistory() {
const onLoadMore = () => { const onLoadMore = () => {
getMessages(selectedConversation); getMessages(selectedConversation);
window.dispatchEvent(new Event('resize')); // window.dispatchEvent(new Event('resize'));
}; };
const loadMore = !loading && selectedConversation.loadNextPage ? ( const loadMore = !loading && selectedConversation.loadNextPage ? (
<div className='text-center pt-3 mb-3 h-8 leading-8 border-dotted border-0 border-t border-slate-300'> <div className='text-center pt-3 mb-3 h-8 leading-8 border-dotted border-0 border-t border-slate-300'>

@ -2,7 +2,7 @@ import { useEffect, useState, useRef } from 'react';
import { useParams, useNavigate, useLocation } from 'react-router-dom'; import { useParams, useNavigate, useLocation } from 'react-router-dom';
import { Button, Dropdown, Input } from 'antd'; import { Button, Dropdown, Input } from 'antd';
import { MoreOutlined } from '@ant-design/icons'; import { MoreOutlined } from '@ant-design/icons';
import { fetchOrderConversationsList, fetchConversationItemClose, fetchMessages, fetchCleanUnreadMsgCount } from '@/actions/ConversationActions'; import { fetchOrderConversationsList, fetchConversationItemClose, fetchMessages, MESSAGE_PAGE_SIZE, fetchCleanUnreadMsgCount } from '@/actions/ConversationActions';
import { ChatList, ChatItem } from 'react-chat-elements'; import { ChatList, ChatItem } from 'react-chat-elements';
import { isEmpty } from '@/utils/utils'; import { isEmpty } from '@/utils/utils';
import useConversationStore from '@/stores/ConversationStore'; import useConversationStore from '@/stores/ConversationStore';
@ -19,7 +19,7 @@ const Conversations = () => {
const userId = useAuthStore((state) => state.loginUser.userId); const userId = useAuthStore((state) => state.loginUser.userId);
const initialState = useConversationStore((state) => state.initialState); const initialState = useConversationStore((state) => state.initialState);
const activeConversations = useConversationStore((state) => state.activeConversations); const activeConversations = useConversationStore((state) => state.activeConversations);
const [currentConversation, setCurrentConversation] = useConversationStore((state) => [state.currentConversation, state.setCurrentConversation]); const [currentConversation, setCurrentConversation, updateCurrentConversation] = useConversationStore((state) => [state.currentConversation, state.setCurrentConversation, state.updateCurrentConversation]);
const conversationsList = useConversationStore((state) => state.conversationsList); const conversationsList = useConversationStore((state) => state.conversationsList);
const addToConversationList = useConversationStore((state) => state.addToConversationList); const addToConversationList = useConversationStore((state) => state.addToConversationList);
const delConversationitem = useConversationStore((state) => state.delConversationitem); const delConversationitem = useConversationStore((state) => state.delConversationitem);
@ -76,6 +76,9 @@ const Conversations = () => {
const data = await fetchMessages({ opisn: userId, whatsappid: item.whatsapp_phone_number, lasttime: '2024-01-01T00:25:30' }); const data = await fetchMessages({ opisn: userId, whatsappid: item.whatsapp_phone_number, lasttime: '2024-01-01T00:25:30' });
setMsgLoading(false); setMsgLoading(false);
receivedMessageList(item.sn, data); receivedMessageList(item.sn, data);
const thisLastTime = data.length > 0 ? data[data.length - 1].orgmsgtime : '';
const loadNextPage = !(data.length === 0 || data.length < MESSAGE_PAGE_SIZE);
updateCurrentConversation({ lasttime: thisLastTime, loadNextPage });
}; };
const switchConversation = async (item) => { const switchConversation = async (item) => {
setCurrentConversation(item); setCurrentConversation(item);

@ -1,37 +1,20 @@
import { useEffect, useRef, useState, forwardRef, memo } from 'react'; import { useEffect, useRef, useState, forwardRef, memo } from 'react';
import { MessageBox } from 'react-chat-elements'; import { MessageBox } from 'react-chat-elements';
import { Button } from 'antd'; import { Button } from 'antd';
import { DownOutlined } from '@ant-design/icons'; import { DownOutlined, LoadingOutlined } from '@ant-design/icons';
import { useShallow } from 'zustand/react/shallow'; import { useShallow } from 'zustand/react/shallow';
import useConversationStore from '@/stores/ConversationStore'; import useConversationStore from '@/stores/ConversationStore';
import { isEmpty, olog } from '@/utils/utils'; import { isEmpty, } from '@/utils/utils';
const MessagesList = ({ messages, handlePreview, reference }) => { const MessagesList = ({ messages, handlePreview, reference, longListLoading, getMoreMessages, shouldScrollBottom, loadNextPage, ...props }) => {
const setReferenceMsg = useConversationStore(useShallow((state) => state.setReferenceMsg)); const setReferenceMsg = useConversationStore(useShallow((state) => state.setReferenceMsg));
// const messagesEndRef = useRef(null); // const messagesEndRef = useRef(null);
const messageRefs = useRef([]); const messageRefs = useRef([]);
const [page, setPage] = useState(1); const prevProps = useRef(props)
let timeout = null;
const fetchNextPage = async () => { const scrollToBottom = (force = false) => {
olog('fetchNextPage') if (reference.current && (shouldScrollBottom || force)) {
setPage(page + 1);
// Fetch next page of messages here
};
const handleScroll = (e) => {
const { scrollTop } = e.target;
const delay = 1000; // 1 second
if (scrollTop === 0) {
if (timeout) clearTimeout(timeout);
timeout = setTimeout(fetchNextPage, delay);
}
};
const scrollToBottom = () => {
if (reference.current) {
reference.current.scrollTop = reference.current.scrollHeight; reference.current.scrollTop = reference.current.scrollHeight;
} }
}; };
@ -45,18 +28,6 @@ const MessagesList = ({ messages, handlePreview, reference }) => {
useEffect(scrollToBottom, [messages]); useEffect(scrollToBottom, [messages]);
useEffect(() => {
const messageList = reference.current;
if (messageList) {
messageList.addEventListener('scroll', handleScroll);
}
return () => {
if (messageList) {
messageList.removeEventListener('scroll', handleScroll);
}
};
}, []);
const RenderText = memo(function renderText({ str }) { const RenderText = memo(function renderText({ str }) {
const parts = str.split(/(https?:\/\/[^\s]+|\p{Emoji_Presentation})/gmu).filter((s) => s !== ''); const parts = str.split(/(https?:\/\/[^\s]+|\p{Emoji_Presentation})/gmu).filter((s) => s !== '');
const links = str.match(/https?:\/\/[\S]+/gi) || []; const links = str.match(/https?:\/\/[\S]+/gi) || [];
@ -90,6 +61,9 @@ const MessagesList = ({ messages, handlePreview, reference }) => {
); );
}); });
const onLoadMore = async () => {
const newLen = await getMoreMessages();
};
// eslint-disable-next-line react/display-name // eslint-disable-next-line react/display-name
const MessageBoxWithRef = forwardRef((props, ref) => ( const MessageBoxWithRef = forwardRef((props, ref) => (
<div ref={ref}> <div ref={ref}>
@ -100,6 +74,11 @@ const MessagesList = ({ messages, handlePreview, reference }) => {
return ( return (
<div className='relative h-full overflow-y-auto overflow-x-hidden flex flex-1'> <div className='relative h-full overflow-y-auto overflow-x-hidden flex flex-1'>
<div ref={reference} className='relative overflow-y-auto overflow-x-hidden block flex-1'> <div ref={reference} className='relative overflow-y-auto overflow-x-hidden block flex-1'>
{loadNextPage && (
<div className='text-center pt-3 mb-3 h-8 leading-8 '>
{!longListLoading ? <Button onClick={onLoadMore} type={'dashed'}>loading more</Button> : <LoadingOutlined className='text-primary' />}
</div>
)}
{messages.map((message, index) => ( {messages.map((message, index) => (
<MessageBoxWithRef <MessageBoxWithRef
ref={(el) => (messageRefs.current[index] = el)} ref={(el) => (messageRefs.current[index] = el)}
@ -137,7 +116,7 @@ const MessagesList = ({ messages, handlePreview, reference }) => {
/> />
))} ))}
</div> </div>
<Button onClick={scrollToBottom} ghost type={'dashed'} shape={'circle'} className=' absolute bottom-1 right-4' icon={<DownOutlined />} /> <Button onClick={() => scrollToBottom(true)} ghost type={'dashed'} shape={'circle'} className=' absolute bottom-1 right-4' icon={<DownOutlined />} />
</div> </div>
); );
}; };

@ -3,20 +3,36 @@ import useConversationStore from '@/stores/ConversationStore';
import { useShallow } from 'zustand/react/shallow'; import { useShallow } from 'zustand/react/shallow';
import { Image, } from 'antd'; import { Image, } from 'antd';
import MessagesList from './MessagesList'; import MessagesList from './MessagesList';
import { fetchCleanUnreadMsgCount } from '@/actions/ConversationActions'; import { fetchCleanUnreadMsgCount, fetchMessages, MESSAGE_PAGE_SIZE } from '@/actions/ConversationActions';
const MessagesWrapper = () => { const MessagesWrapper = () => {
const currentConversation = useConversationStore(useShallow((state) => state.currentConversation)); const [currentConversation, updateCurrentConversation] = useConversationStore(useShallow((state) => [state.currentConversation, state.updateCurrentConversation]));
const activeMessages = useConversationStore(useShallow((state) => (state.currentConversation.sn && state.activeConversations[state.currentConversation.sn] ? state.activeConversations[state.currentConversation.sn]: []))); const activeMessages = useConversationStore(useShallow((state) => (state.currentConversation.sn && state.activeConversations[state.currentConversation.sn] ? state.activeConversations[state.currentConversation.sn]: [])));
const [longList, setLongList] = useState([]);
const [longListLoading, setLongListLoading] = useState(false);
const [shouldScrollBottom, setShouldScrollBottom] = useState(true);
useEffect(() => { useEffect(() => {
setLongList(activeMessages);
setShouldScrollBottom(true);
if (currentConversation.opi_sn && currentConversation.whatsapp_phone_number && activeMessages.length > 0) { if (currentConversation.opi_sn && currentConversation.whatsapp_phone_number && activeMessages.length > 0) {
fetchCleanUnreadMsgCount({ opisn: currentConversation.opi_sn, whatsappid: currentConversation.whatsapp_phone_number }); fetchCleanUnreadMsgCount({ opisn: currentConversation.opi_sn, whatsappid: currentConversation.whatsapp_phone_number });
} }
return () => {}; return () => {};
}, [activeMessages]); }, [activeMessages, currentConversation.sn]);
const getMoreMessages = async () => {
setShouldScrollBottom(false);
setLongListLoading(true);
const data = await fetchMessages({ opisn: currentConversation.opi_sn, whatsappid: currentConversation.whatsapp_phone_number, lasttime: currentConversation?.lasttime || '2024-01-01T00:00:00' });
setLongListLoading(false);
setLongList(prevValue => data.concat(prevValue));
const thisLastTime = data.length > 0 ? data[data.length - 1].orgmsgtime : '';
const loadNextPage = !(data.length === 0 || data.length < MESSAGE_PAGE_SIZE);
updateCurrentConversation({ lasttime: thisLastTime, loadNextPage });
return data.length;
};
const reference = useRef(null); const reference = useRef(null);
@ -43,7 +59,7 @@ const MessagesWrapper = () => {
}; };
return ( return (
<> <>
<MessagesList messages={activeMessages} {...{ reference, handlePreview }} /> <MessagesList messages={longList} dataSourceLen={longList.length} {...{ reference, handlePreview, longListLoading, setLongListLoading, getMoreMessages, shouldScrollBottom, loadNextPage: currentConversation?.loadNextPage ?? true }} />
<Image width={0} height={0} src={null} preview={{ visible: previewVisible, src: previewSrc, onClose: onPreviewClose }} /> <Image width={0} height={0} src={null} preview={{ visible: previewVisible, src: previewSrc, onClose: onPreviewClose }} />
</> </>
); );

Loading…
Cancel
Save