todo: 历史记录

dev/chat
Lei OT 2 years ago
parent 3bbe967b4c
commit 92a423ab31

@ -12,12 +12,20 @@ export const fetchTemplates = async () => {
return canUseTemplates;
};
/**
*
* @param {object} params { opisn }
*/
export const fetchConversationsList = async (params) => {
const { result: data } = await fetchJSON(`${API_HOST}/getconversations`, params);
const list = data.map((ele) => ({ ...ele, customer_name: ele.whatsapp_name.trim() }));
const list = (data || []).map((ele) => ({ ...ele, customer_name: ele.whatsapp_name.trim() }));
return list;
};
/**
*
* @param {object} params { opisn, whatsappid, }
*/
export const fetchMessages = async (params) => {
const { result } = await fetchJSON(`${API_HOST}/getcusmessages`, params);
return parseRenderMessageList(result || []);
@ -29,6 +37,10 @@ export const fetchCustomerProfile = async (colisn) => {
return data;
};
/**
*
* @param {object} params { opisn, whatsappid, colisn }
*/
export const fetchOrderConversationsList = async (params) => {
const { errcode, result: data } = await fetchJSON(`${API_HOST}/getorderconversation`, params);
if (errcode !== 0) return [];
@ -39,7 +51,6 @@ export const fetchOrderConversationsList = async (params) => {
/**
*
* @param {object} body { opisn, conversationid }
* @returns
*/
export const fetchConversationItemClose = async (body) => {
const { result } = await fetchJSON(`${API_HOST}/closeconversation`, body);

@ -451,6 +451,7 @@ export const parseRenderMessageList = (messages, conversationid = null) => {
type: msgContent.type,
...(typeof whatsappMsgTypeMapped[msgType].type === 'function' ? whatsappMsgTypeMapped[msgType].type(msg) : { type: whatsappMsgTypeMapped[msgType].type || 'text' }),
date: msgContent?.sendTime || msg.msgtime || '',
localDate: msg.msgtime || '',
from: msgContent.from,
sender: msgContent.from,
senderName: msgContent?.customerProfile?.name || msgContent.from,

@ -1,13 +1,15 @@
import { useNavigate } from 'react-router-dom';
import { memo, useCallback, useEffect, useRef, useState } from 'react';
import { Row, Col, Divider, Table, Card, Button, Input, Flex, Layout, Space, Empty, Radio, Select, DatePicker, Form, List, Avatar } from 'antd';
import { memo, useCallback, useEffect, useRef, useState, forwardRef } from 'react';
import { Row, Col, Divider, Table, Card, Button, Input, Flex, Layout, Space, Empty, Radio, Select, DatePicker, Form, List, Avatar, Spin, Image } from 'antd';
import { StarFilled, ZoomInOutlined, StarOutlined, SearchOutlined } from '@ant-design/icons';
import { ChatList, ChatItem, MessageBox } from 'react-chat-elements';
import { fetchConversationsList, fetchMessages } from '@/actions/ConversationActions';
import { isEmpty } from '@/utils/utils';
const { Sider, Content, Header, Footer } = Layout;
const { Search } = Input;
const { RangePicker } = DatePicker;
// 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
const data = [
{
title: 'Ann',
@ -82,12 +84,16 @@ const SearchForm = memo(function ({ onSubmit }) {
optionFilterProp='children'
filterOption={(input, option) => (option?.label ?? '').toLowerCase().includes(input.toLowerCase())}
options={[
{
value: '354',
label: '宁艳',
},
{
value: '杨新玲',
label: '杨新玲',
},
{
value: '黄雪荣',
value: '495',
label: '黄雪荣',
},
{
@ -185,39 +191,172 @@ function ChatHistory() {
setFormValues({ ...values });
}, []);
const [loading, setLoading] = useState(false);
const [conversationsList, setConversationsList] = useState([]);
const [selectedConversation, setSelectedConversation] = useState({});
const [chatItemMessages, setChatItemMessages] = useState([]);
const getConversationsList = async () => {
setLoading(true);
setChatItemMessages([]);
const data = await fetchConversationsList({ opisn: formValues.travel });
setLoading(false);
setConversationsList(data);
if (data.length === 1) {
setSelectedConversation(data[0]);
await getMessages(data[0]);
}
};
const getMessages = async (chatItem) => {
setLoading(true);
setChatItemMessages([]);
const data = await fetchMessages({ opisn: chatItem.opi_sn, whatsappid: chatItem.whatsapp_phone_number });
setLoading(false);
setChatItemMessages(data);
};
useEffect(() => {
if (selectedConversation.whatsapp_phone_number) {
getMessages(selectedConversation);
}
return () => {};
}, [selectedConversation]);
useEffect(() => {
if (formValues.travel) {
getConversationsList();
}
return () => {};
}, [formValues]);
const RenderText = memo(function renderText({ str }) {
const parts = str.split(/(https?:\/\/[^\s]+|\p{Emoji_Presentation})/gmu).filter((s) => s !== '');
const links = str.match(/https?:\/\/[\S]+/gi) || [];
const emojis = str.match(/([\u2700-\u27BF]|[\uE000-\uF8FF]|\uD83C[\uDC00-\uDFFF]|\uD83D[\uDC00-\uDFFF]|[\u2011-\u26FF]|\uD83E[\uDD10-\uDDFF])/g) || [];
const extraClass = isEmpty(emojis) ? '' : 'text-base leading-5 emoji-text';
const objArr = parts.reduce((prev, curr, index) => {
if (links.includes(curr)) {
prev.push({ type: 'link', key: curr });
} else if (emojis.includes(curr)) {
prev.push({ type: 'emoji', key: curr });
} else {
prev.push({ type: 'text', key: curr });
}
return prev;
}, []);
return (
<span className={extraClass}>
{(objArr || []).map((part, index) => {
if (part.type === 'link') {
return (
<a href={part.key} target='_blank' key={`${part.key}${index}`} rel='noreferrer' className='text-sm'>
{part.key}
</a>
);
} else {
// if (part.type === 'emoji')
return part.key;
}
})}
</span>
);
});
const handlePreview = (msg) => {
switch (msg.whatsapp_msg_type) {
case 'image':
// eslint-disable-next-line no-fallthrough
case 'document':
window.open(msg.data.link || msg.data.uri, '_blank', 'noopener,noreferrer');
return false;
default:
return false;
}
};
const messagesEndRef = useRef(null);
const messageRefs = useRef([]);
const scrollToMessage = (id, index) => {
const _i = index || chatItemMessages.findIndex((msg) => msg.id === id);
if (_i >= 0) {
messageRefs.current[_i].scrollIntoView({ behavior: 'smooth', block: 'start' });
}
};
// eslint-disable-next-line react/display-name
const MessageBoxWithRef = forwardRef((props, ref) => (
<li ref={ref}>
<MessageBox {...props} />
</li>
));
return (
<>
<SearchForm onSubmit={handleSubmit} />
<Divider plain orientation='left'></Divider>
<Layout hasSider className='h-screen chathistory-wrapper' style={{ maxHeight: 'calc(100% - 279px)', height: 'calc(100% - 279px)' }}>
<Sider width={240} theme={'light'} className='h-full overflow-y-auto' style={{ maxHeight: 'calc(100vh - 279px)', height: 'calc(100vh - 279px)' }}>
<ChatList
className={'__active text-primary '}
dataSource={[
{
alt: 'Jane',
title: 'Jane',
date: new Date(),
letterItem: { id: 'x1', letter: 'Jane' },
},
]}
/>
<Layout hasSider className='h-screen chathistory-wrapper chatwindow-wrapper' style={{ maxHeight: 'calc(100% - 279px)', height: 'calc(100% - 279px)' }}>
<Sider width={240} theme={'light'} className='h-full overflow-y-auto overflow-x-hidden' style={{ maxHeight: 'calc(100vh - 279px)', height: 'calc(100vh - 279px)' }}>
<Spin spinning={loading}>
{conversationsList.map((item) => (
<ChatItem
{...item}
key={item.sn}
id={item.sn}
letterItem={{ id: item.whatsapp_name.trim() || item.whatsapp_phone_number, letter: (item.whatsapp_name.trim() || item.whatsapp_phone_number).slice(0, 5) }}
alt={`${item.whatsapp_name.trim()}`}
title={item.whatsapp_name.trim() || item.whatsapp_phone_number}
subtitle={item.coli_id}
date={item.last_received_time}
className={String(item.sn) === String(selectedConversation.sn) ? '__active text-primary bg-neutral-100' : ''}
onClick={() => setSelectedConversation(item)}
/>
))}
</Spin>
</Sider>
<Content style={{ maxHeight: 'calc(100vh - 279px)', height: 'calc(100vh - 279px)', minWidth: '360px' }}>
<div className='h-full relative'>
<div className='h-full relative' ref={messagesEndRef}>
<List
loading={false}
loading={loading}
loadMore={() => {
console.log('load more');
}}
className='h-full overflow-y-auto px-2'
className='h-full overflow-y-auto px-2 relative'
itemLayout='vertical'
dataSource={data}
renderItem={(item, index) => (
<List.Item>
<List.Item.Meta avatar={<Avatar src={item.avatarUrl} />} title={item.title} description={item.msgTime} />
<div>{item.content}</div>
</List.Item>
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}
text={<RenderText str={message?.text || ''} />}
dateString={message.dateString || message.localDate}
className={['whitespace-pre-wrap', message.whatsapp_msg_type === 'sticker' ? 'bg-transparent' : '', message.sender === 'me' ? 'whatsappme-container' : ''].join(
' '
)}
style={{
backgroundColor: message.sender === 'me' ? '#ccd4ae' : '#fff',
}}
{...(message.type === 'meetingLink'
? {
actionButtons: [
{
onClickButton: () => {
navigator.clipboard.writeText(message.text);
},
Component: () => <div>复制</div>,
},
],
}
: {})}
/>
)}
/>
</div>

Loading…
Cancel
Save