|
|
|
@ -1,5 +1,5 @@
|
|
|
|
|
import { memo, useCallback, useEffect, useRef, useState, forwardRef } from 'react';
|
|
|
|
|
import { Divider, Button, Input, Layout, DatePicker, Form, List, Spin, Flex } from 'antd';
|
|
|
|
|
import { Divider, Button, Input, Layout, DatePicker, Form, List, Spin, Flex, Image } from 'antd';
|
|
|
|
|
import { LoadingOutlined } from '@ant-design/icons';
|
|
|
|
|
import { ChatItem, MessageBox } from 'react-chat-elements';
|
|
|
|
|
import { MESSAGE_PAGE_SIZE, fetchConversationsSearch, fetchMessagesHistory } from '@/actions/ConversationActions';
|
|
|
|
@ -83,13 +83,14 @@ function ChatHistory() {
|
|
|
|
|
const [messageListLoading, setMessageListLoading] = useState(false);
|
|
|
|
|
const [conversationsList, setConversationsList] = useState([]);
|
|
|
|
|
const [chatItemMessages, setChatItemMessages] = useState([]);
|
|
|
|
|
const [imageAlbum, setImageAlbum] = useState([]);
|
|
|
|
|
// const [paramsForMsgList, setParamsForMsgList] = useState({ loadNextPage: true, loadPrePage: true, }); // { opisn, whatsappid, lasttime, pagesize, pagedir }
|
|
|
|
|
// const [selectMatch, setSelectedMatch] = useState({});
|
|
|
|
|
|
|
|
|
|
const getConversationsList = async () => {
|
|
|
|
|
const allEmpty = Object.values(cloneDeep(formValues)).every((val) => {
|
|
|
|
|
return val === null || val === '' || val === undefined;
|
|
|
|
|
});
|
|
|
|
|
// const allEmpty = Object.values(cloneDeep(formValues)).every((val) => {
|
|
|
|
|
// return val === null || val === '' || val === undefined;
|
|
|
|
|
// });
|
|
|
|
|
// if (allEmpty) return;
|
|
|
|
|
setConversationsListLoading(true);
|
|
|
|
|
setChatItemMessages([]);
|
|
|
|
@ -180,6 +181,7 @@ function ChatHistory() {
|
|
|
|
|
useEffect(() => {
|
|
|
|
|
if (chatItemMessages.length > 0) {
|
|
|
|
|
setParamsForMsgList({pretime: chatItemMessages[0].orgmsgtime, lasttime: chatItemMessages[chatItemMessages.length - 1].orgmsgtime });
|
|
|
|
|
setImageAlbum(chatItemMessages.filter(ele => ele.whatsapp_msg_type === 'image').map(ele => ele.data.uri));
|
|
|
|
|
}
|
|
|
|
|
return () => {};
|
|
|
|
|
}, [chatItemMessages])
|
|
|
|
@ -241,7 +243,30 @@ function ChatHistory() {
|
|
|
|
|
);
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
const [previewVisible, setPreviewVisible] = useState(false);
|
|
|
|
|
const [previewSrc, setPreviewSrc] = useState();
|
|
|
|
|
const [previewIndex, setPreviewIndex] = useState();
|
|
|
|
|
const onPreviewClose = () => {
|
|
|
|
|
setPreviewSrc('');
|
|
|
|
|
setPreviewVisible(false);
|
|
|
|
|
};
|
|
|
|
|
const handlePreview = (msg) => {
|
|
|
|
|
switch (msg.whatsapp_msg_type) {
|
|
|
|
|
case 'image':
|
|
|
|
|
setPreviewVisible(true);
|
|
|
|
|
setPreviewSrc(msg.data.uri);
|
|
|
|
|
setPreviewIndex(imageAlbum.findIndex((url) => url === msg.data.uri));
|
|
|
|
|
return false;
|
|
|
|
|
|
|
|
|
|
case 'document':
|
|
|
|
|
window.open(msg.data.link || msg.data.uri, '_blank', 'noopener,noreferrer');
|
|
|
|
|
return false;
|
|
|
|
|
|
|
|
|
|
default:
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
const handlePreviewItem = (msg) => {
|
|
|
|
|
switch (msg.whatsapp_msg_type) {
|
|
|
|
|
case 'image':
|
|
|
|
|
// eslint-disable-next-line no-fallthrough
|
|
|
|
@ -282,7 +307,7 @@ function ChatHistory() {
|
|
|
|
|
{...item}
|
|
|
|
|
key={item.conversationid}
|
|
|
|
|
id={item.conversationid}
|
|
|
|
|
letterItem={{ id: item.whatsapp_name || item.whatsapp_phone_number, letter: (item.whatsapp_name || item.whatsapp_phone_number).split(" ")[0] }}
|
|
|
|
|
letterItem={{ id: item.whatsapp_name || item.whatsapp_phone_number, letter: (item.whatsapp_name || item.whatsapp_phone_number).split(' ')[0] }}
|
|
|
|
|
alt={`${item.whatsapp_name}`}
|
|
|
|
|
title={item.whatsapp_name || item.whatsapp_phone_number}
|
|
|
|
|
subtitle={`${item.OPI_Name || ''} ${item.coli_id || ''}`}
|
|
|
|
@ -295,14 +320,19 @@ function ChatHistory() {
|
|
|
|
|
</Spin>
|
|
|
|
|
</Sider>
|
|
|
|
|
<Content style={{ maxHeight: 'calc(100vh - 279px)', height: 'calc(100vh - 279px)', minWidth: '360px' }}>
|
|
|
|
|
<Flex className='h-full relative'>
|
|
|
|
|
{(selectedConversation.matchMsgList || []).length > 1 && isNotEmpty(formValues.search) && <div className='w-80 overflow-y-auto overflow-x-hidden'>
|
|
|
|
|
{(selectedConversation.matchMsgList).map((item) => (
|
|
|
|
|
<Flex className='h-full relative'>
|
|
|
|
|
{(selectedConversation.matchMsgList || []).length > 1 && isNotEmpty(formValues.search) && (
|
|
|
|
|
<div className='w-80 overflow-y-auto overflow-x-hidden'>
|
|
|
|
|
<p className='text-center'><mark>{formValues.search}</mark> 的相关记录, 点击定位上下文</p>
|
|
|
|
|
{selectedConversation.matchMsgList.map((item) => (
|
|
|
|
|
<ChatItem
|
|
|
|
|
{...item}
|
|
|
|
|
key={item.sn}
|
|
|
|
|
id={item.sn}
|
|
|
|
|
letterItem={{ id: (item.sender === 'me' ? (selectedConversation.OPI_Name || item.senderName) : item.senderName), letter: (item.sender === 'me' ? (selectedConversation.OPI_Name || item.senderName) : item.senderName).split(" ")[0] }}
|
|
|
|
|
letterItem={{
|
|
|
|
|
id: item.sender === 'me' ? selectedConversation.OPI_Name || item.senderName : item.senderName,
|
|
|
|
|
letter: (item.sender === 'me' ? selectedConversation.OPI_Name || item.senderName : item.senderName).split(' ')[0],
|
|
|
|
|
}}
|
|
|
|
|
alt={`${item.senderName}`}
|
|
|
|
|
title={item.senderName}
|
|
|
|
|
subtitle={item.originText}
|
|
|
|
@ -312,70 +342,77 @@ function ChatHistory() {
|
|
|
|
|
onClick={() => handleMatchMsgClick(item)}
|
|
|
|
|
/>
|
|
|
|
|
))}
|
|
|
|
|
</div>}
|
|
|
|
|
<div className='h-full relative flex-1 border-dashed border-y-0 border-r-0 border-l border-slate-200' ref={messagesEndRef}>
|
|
|
|
|
<List
|
|
|
|
|
loading={messageListLoading}
|
|
|
|
|
header={loadMorePre}
|
|
|
|
|
loadMore={loadMore}
|
|
|
|
|
className='h-full overflow-y-auto px-2 relative'
|
|
|
|
|
itemLayout='vertical'
|
|
|
|
|
dataSource={chatItemMessages}
|
|
|
|
|
renderItem={(message, index) => (
|
|
|
|
|
// <List.Item>
|
|
|
|
|
// <List.Item.Meta avatar={<Avatar src={item.avatarUrl} />} title={item.title} description={item.msgTime} />
|
|
|
|
|
// <div>{item.content}</div>
|
|
|
|
|
// </List.Item>
|
|
|
|
|
<MessageBoxWithRef
|
|
|
|
|
ref={(el) => (messageRefs.current[index] = el)}
|
|
|
|
|
key={message.id}
|
|
|
|
|
{...message}
|
|
|
|
|
// position={message.sender === 'me' ? 'right' : 'left'}
|
|
|
|
|
position={'left'}
|
|
|
|
|
onReplyMessageClick={() => scrollToMessage(message.reply.id)}
|
|
|
|
|
onOpen={() => handlePreview(message)}
|
|
|
|
|
onTitleClick={() => handlePreview(message)}
|
|
|
|
|
notch={false}
|
|
|
|
|
title={message.whatsapp_msg_type === 'text' ? '' : message.title}
|
|
|
|
|
text={<RenderText str={message?.text || ''} className={message.status === 'failed' ? 'line-through text-neutral-400' : ''} />}
|
|
|
|
|
copiableDate={true}
|
|
|
|
|
dateString={message.dateString || message.localDate}
|
|
|
|
|
className={[
|
|
|
|
|
'whitespace-pre-wrap mb-2',
|
|
|
|
|
message.whatsapp_msg_type === 'sticker' ? 'bg-transparent' : '',
|
|
|
|
|
message.sender === 'me' ? 'whatsappme-container' : '',
|
|
|
|
|
focusMsg === message.id ? 'message-box-focus' : '',
|
|
|
|
|
message.status === 'failed' ? 'failed-msg' : '',
|
|
|
|
|
].join(' ')}
|
|
|
|
|
style={{
|
|
|
|
|
backgroundColor: message.sender === 'me' ? '#ccd4ae' : '#fff',
|
|
|
|
|
}}
|
|
|
|
|
{...(message.type === 'meetingLink'
|
|
|
|
|
? {
|
|
|
|
|
actionButtons: [
|
|
|
|
|
{
|
|
|
|
|
onClickButton: () => {
|
|
|
|
|
navigator.clipboard.writeText(message.text);
|
|
|
|
|
},
|
|
|
|
|
Component: () => <div>复制</div>,
|
|
|
|
|
},
|
|
|
|
|
],
|
|
|
|
|
}
|
|
|
|
|
: {})}
|
|
|
|
|
renderAddCmp={
|
|
|
|
|
<div className='border-dashed border-0 border-t border-slate-300 text-slate-600 space-x-2 emoji'>
|
|
|
|
|
<span className={`p-1 rounded-b ${message.msg_direction === 'outbound' ? 'text-white' : ''} `} style={{backgroundColor: message.msg_direction === 'outbound' ? stringToColour(message.senderName) : 'unset'}}>{message.msg_direction === 'outbound' ? selectedConversation.OPI_Name : message.senderName}</span>
|
|
|
|
|
<span>{message.dateString || message.localDate}</span>
|
|
|
|
|
<span>{message.statusCN}</span>
|
|
|
|
|
</div>
|
|
|
|
|
}
|
|
|
|
|
// date={null}
|
|
|
|
|
// status={null}
|
|
|
|
|
/>
|
|
|
|
|
)}
|
|
|
|
|
/>
|
|
|
|
|
</div>
|
|
|
|
|
</Flex>
|
|
|
|
|
)}
|
|
|
|
|
<div className='h-full relative flex-1 border-dashed border-y-0 border-r-0 border-l border-slate-200' ref={messagesEndRef}>
|
|
|
|
|
<List
|
|
|
|
|
loading={messageListLoading}
|
|
|
|
|
header={loadMorePre}
|
|
|
|
|
loadMore={loadMore}
|
|
|
|
|
className='h-full overflow-y-auto px-2 relative'
|
|
|
|
|
itemLayout='vertical'
|
|
|
|
|
dataSource={chatItemMessages}
|
|
|
|
|
renderItem={(message, index) => (
|
|
|
|
|
// <List.Item>
|
|
|
|
|
// <List.Item.Meta avatar={<Avatar src={item.avatarUrl} />} title={item.title} description={item.msgTime} />
|
|
|
|
|
// <div>{item.content}</div>
|
|
|
|
|
// </List.Item>
|
|
|
|
|
<MessageBoxWithRef
|
|
|
|
|
ref={(el) => (messageRefs.current[index] = el)}
|
|
|
|
|
key={message.id}
|
|
|
|
|
{...message}
|
|
|
|
|
// position={message.sender === 'me' ? 'right' : 'left'}
|
|
|
|
|
position={'left'}
|
|
|
|
|
onReplyMessageClick={() => scrollToMessage(message.reply.id)}
|
|
|
|
|
onOpen={() => handlePreview(message)}
|
|
|
|
|
onTitleClick={() => handlePreview(message)}
|
|
|
|
|
notch={false}
|
|
|
|
|
title={message.whatsapp_msg_type === 'text' ? '' : message.title}
|
|
|
|
|
text={<RenderText str={message?.text || ''} className={message.status === 'failed' ? 'line-through text-neutral-400' : ''} />}
|
|
|
|
|
copiableDate={true}
|
|
|
|
|
dateString={message.dateString || message.localDate}
|
|
|
|
|
className={[
|
|
|
|
|
'whitespace-pre-wrap mb-2',
|
|
|
|
|
message.whatsapp_msg_type === 'sticker' ? 'bg-transparent' : '',
|
|
|
|
|
message.sender === 'me' ? 'whatsappme-container' : '',
|
|
|
|
|
focusMsg === message.id ? 'message-box-focus' : '',
|
|
|
|
|
message.status === 'failed' ? 'failed-msg' : '',
|
|
|
|
|
].join(' ')}
|
|
|
|
|
style={{
|
|
|
|
|
backgroundColor: message.sender === 'me' ? '#ccd4ae' : '#fff',
|
|
|
|
|
}}
|
|
|
|
|
{...(message.type === 'meetingLink'
|
|
|
|
|
? {
|
|
|
|
|
actionButtons: [
|
|
|
|
|
{
|
|
|
|
|
onClickButton: () => {
|
|
|
|
|
navigator.clipboard.writeText(message.text);
|
|
|
|
|
},
|
|
|
|
|
Component: () => <div>复制</div>,
|
|
|
|
|
},
|
|
|
|
|
],
|
|
|
|
|
}
|
|
|
|
|
: {})}
|
|
|
|
|
renderAddCmp={
|
|
|
|
|
<div className='border-dashed border-0 border-t border-slate-300 text-slate-600 space-x-2 emoji'>
|
|
|
|
|
<span
|
|
|
|
|
className={`p-1 rounded-b ${message.msg_direction === 'outbound' ? 'text-white' : ''} `}
|
|
|
|
|
style={{ backgroundColor: message.msg_direction === 'outbound' ? stringToColour(message.senderName) : 'unset' }}>
|
|
|
|
|
{message.msg_direction === 'outbound' ? selectedConversation.OPI_Name : message.senderName}
|
|
|
|
|
</span>
|
|
|
|
|
<span>{message.dateString || message.localDate}</span>
|
|
|
|
|
<span>{message.statusCN}</span>
|
|
|
|
|
</div>
|
|
|
|
|
}
|
|
|
|
|
// date={null}
|
|
|
|
|
// status={null}
|
|
|
|
|
/>
|
|
|
|
|
)}
|
|
|
|
|
/>
|
|
|
|
|
</div>
|
|
|
|
|
</Flex>
|
|
|
|
|
{/* <Image width={0} height={0} src={null} preview={{ visible: previewVisible, src: previewSrc, onClose: onPreviewClose }} /> */}
|
|
|
|
|
<Image.PreviewGroup items={imageAlbum} preview={{ current: previewIndex, visible: previewVisible, onClose: onPreviewClose, onChange: setPreviewIndex }} />
|
|
|
|
|
</Content>
|
|
|
|
|
</Layout>
|
|
|
|
|
</>
|
|
|
|
|