页面刷新后定位; 消息原文原始对象

dev/mobile
Lei OT 2 years ago
parent 6979a1eabf
commit 77bde97ee1

@ -31,7 +31,7 @@ export const sentMsgTypeMapped = {
renderId: msg.id, renderId: msg.id,
to: msg.to, to: msg.to,
msgtype: 'text', msgtype: 'text',
msgcontent: { body: msg.text, ...(msg.context ? { context: msg.context, message_origin: msg.message_origin } : {}) }, msgcontent: { body: msg.text, ...(msg.context ? { context: msg.context, message_origin: msg.message_origin.msgOrigin } : {}) },
}), }),
contentToRender: (msg) => ({ contentToRender: (msg) => ({
...msg, ...msg,
@ -39,7 +39,12 @@ export const sentMsgTypeMapped = {
conversationid: msg.id.split('.')[0], conversationid: msg.id.split('.')[0],
...(msg.context ...(msg.context
? { ? {
reply: { message: msg.message_origin.text, title: msg.message_origin.senderName || 'Reference' }, reply: {
message: msg.message_origin.text,
title: msg.message_origin.senderName || 'Reference',
titleColor: msg.message_origin?.senderName !== 'me' ? '#a791ff' : "#128c7e",
// titleColor: "#a791ff",
},
} }
: {}), : {}),
}), }),
@ -63,7 +68,7 @@ export const sentMsgTypeMapped = {
conversationid: msg.id.split('.')[0], conversationid: msg.id.split('.')[0],
...(msg.context ...(msg.context
? { ? {
reply: { message: msg.message_origin.text, title: msg.message_origin.senderName || 'Reference' }, reply: { message: msg.message_origin.text, title: msg.message_origin.senderName || 'Reference', titleColor: "#a791ff", },
} }
: {}), : {}),
}), }),
@ -91,7 +96,7 @@ const whatsappMsgMapped = {
'whatsapp.inbound_message.received': { 'whatsapp.inbound_message.received': {
getMsg: (result) => { getMsg: (result) => {
console.log('whatsapp.inbound_message.received', result); console.log('whatsapp.inbound_message.received', result);
return isEmpty(result?.whatsappInboundMessage) ? null : { ...result.whatsappInboundMessage, conversationid: result.conversationid }; return isEmpty(result?.whatsappInboundMessage) ? null : { ...result.whatsappInboundMessage, conversationid: result.conversationid, messageorigin: result.messageorigin };
}, },
contentToRender: (contentObj) => { contentToRender: (contentObj) => {
console.log('whatsapp.inbound_message.received to render', contentObj); console.log('whatsapp.inbound_message.received to render', contentObj);
@ -165,6 +170,7 @@ export const whatsappMsgTypeMapped = {
text: { text: {
type: 'text', type: 'text',
data: (msg) => ({ id: msg.wamid, text: msg.text.body }), data: (msg) => ({ id: msg.wamid, text: msg.text.body }),
renderForReply: (msg) => ({ id: msg.wamid, message: msg.text.body }),
}, },
image: { image: {
type: 'photo', type: 'photo',
@ -216,7 +222,7 @@ export const whatsappMsgTypeMapped = {
unsupported: { type: 'system', data: (msg) => ({ text: 'Message type is currently not supported.' }) }, unsupported: { type: 'system', data: (msg) => ({ text: 'Message type is currently not supported.' }) },
reaction: { reaction: {
type: 'text', type: 'text',
data: (msg) => ({ id: msg.wamid, text: msg.reaction?.emoji || msg.reaction?.text?.body || 'Reaction', reply: { message: '{content}', title: 'React from', titleColor: '#1ba784' } }), // todo: data: (msg) => ({ id: msg.wamid, text: msg.reaction?.emoji || '', }),
}, },
document: { document: {
type: 'file', type: 'file',
@ -234,8 +240,8 @@ export const whatsappMsgTypeMapped = {
return { id: msg.wamid, text: templateDataMapped?.body?.text || templateDataMapped?.body?.parameters?.[0]?.text || '', title: msg.template.name } return { id: msg.wamid, text: templateDataMapped?.body?.text || templateDataMapped?.body?.parameters?.[0]?.text || '', title: msg.template.name }
}, },
renderForReply: (msg) => { renderForReply: (msg) => {
const templateDataMapped = msg.template?.components ? msg.template.components.reduce((r, v) => ({...r, [v.type]: v}), {}) : null; const templateDataMapped = msg.template?.components ? msg.template.components.reduce((r, v) => ({ ...r, [v.type]: v }), {}) : null;
return { id: msg.wamid, message: templateDataMapped?.body?.text || templateDataMapped?.body?.parameters?.[0]?.text || '', title: `${msg.template.name}` } return { id: msg.wamid, message: templateDataMapped?.body?.text || templateDataMapped?.body?.parameters?.[0]?.text || '', title: `${msg.template.name}` };
}, },
}, },
}; };
@ -245,11 +251,13 @@ export const whatsappMsgTypeMapped = {
export const parseRenderMessageItem = (msg) => { export const parseRenderMessageItem = (msg) => {
console.log('parseRenderMessageItem', msg); console.log('parseRenderMessageItem', msg);
return { return {
msgOrigin: msg,
date: msg?.sendTime || msg?.createTime || '', date: msg?.sendTime || msg?.createTime || '',
...(whatsappMsgTypeMapped?.[msg.type]?.data(msg) || {}), ...(whatsappMsgTypeMapped?.[msg.type]?.data(msg) || {}),
conversationid: msg.conversationid, conversationid: msg.conversationid,
...(typeof whatsappMsgTypeMapped[msg.type].type === 'function' ? whatsappMsgTypeMapped[msg.type].type(msg) : { type: whatsappMsgTypeMapped[msg.type].type || 'text' }), ...(typeof whatsappMsgTypeMapped[msg.type].type === 'function' ? whatsappMsgTypeMapped[msg.type].type(msg) : { type: whatsappMsgTypeMapped[msg.type].type || 'text' }),
// type: whatsappMsgTypeMapped?.[msg.type]?.type || 'text', // type: whatsappMsgTypeMapped?.[msg.type]?.type || 'text',
from: msg.from,
sender: msg.from, sender: msg.from,
senderName: msg?.customerProfile?.name || msg.from, senderName: msg?.customerProfile?.name || msg.from,
// title: msg.customerProfile.name, // title: msg.customerProfile.name,
@ -257,13 +265,18 @@ export const parseRenderMessageItem = (msg) => {
whatsapp_name: msg?.customerProfile?.name || '', whatsapp_name: msg?.customerProfile?.name || '',
whatsapp_phone_number: msg.from, whatsapp_phone_number: msg.from,
whatsapp_msg_type: msg.type, whatsapp_msg_type: msg.type,
...(isEmpty(msg.context) ...(isEmpty(msg.context) && isEmpty(msg.reaction)
? {} ? {}
: { : {
reply: { reply: {
message: `${msg.context.id}`, // todo: msg.context.text?.body || msg.context.text, /**
title: msg?.customerProfile?.name || msg.from, * reply: { message: msg.messageorigin, title: 'React from', titleColor: '#1ba784' }
titleColor: "#53bdeb", // "#128c7e", */
title: msg.messageorigin?.customerProfile?.name || 'me',
...(typeof whatsappMsgTypeMapped[msg?.messageorigin?.type]?.renderForReply === 'function'
? whatsappMsgTypeMapped[msg.messageorigin.type].renderForReply(msg.messageorigin)
: {}),
titleColor: msg.messageorigin?.customerProfile?.name ? '#a791ff' : "#128c7e",
}, },
origin: msg.context, origin: msg.context,
}), }),
@ -279,10 +292,12 @@ export const parseRenderMessageList = (messages, conversationid = null) => {
const msgType = msgContent.type; const msgType = msgContent.type;
// const parseMethod = msgContent.bizType === 'whatsapp' ? cloneDeep(whatsappMsgTypeMapped) : {}; // const parseMethod = msgContent.bizType === 'whatsapp' ? cloneDeep(whatsappMsgTypeMapped) : {};
return { return {
msgOrigin: msgContent,
...(whatsappMsgTypeMapped?.[msgType]?.data(msgContent) || {}), ...(whatsappMsgTypeMapped?.[msgType]?.data(msgContent) || {}),
type: msgContent.type, type: msgContent.type,
...(typeof whatsappMsgTypeMapped[msgType].type === 'function' ? whatsappMsgTypeMapped[msgType].type(msg) : { type: whatsappMsgTypeMapped[msgType].type || 'text' }), ...(typeof whatsappMsgTypeMapped[msgType].type === 'function' ? whatsappMsgTypeMapped[msgType].type(msg) : { type: whatsappMsgTypeMapped[msgType].type || 'text' }),
date: msgContent?.sendTime || msg.msgtime || '', date: msgContent?.sendTime || msg.msgtime || '',
from: msgContent.from,
sender: msgContent.from, sender: msgContent.from,
senderName: msgContent?.customerProfile?.name || msgContent.from, senderName: msgContent?.customerProfile?.name || msgContent.from,
...(msg.msg_direction === 'outbound' ...(msg.msg_direction === 'outbound'
@ -298,11 +313,12 @@ export const parseRenderMessageList = (messages, conversationid = null) => {
: { : {
reply: { reply: {
message: msg.messageorigin_AsJOSN.text?.body || msg.messageorigin_AsJOSN.text, message: msg.messageorigin_AsJOSN.text?.body || msg.messageorigin_AsJOSN.text,
title: msg.messageorigin_AsJOSN.senderName || '@', // msg.messageorigin_AsJOSN.from title: msg.messageorigin_AsJOSN?.customerProfile?.name || 'me', // msg.messageorigin_AsJOSN.senderName || '@',
...(typeof whatsappMsgTypeMapped[msg.messageorigin_AsJOSN.type]?.renderForReply === 'function' ...(typeof whatsappMsgTypeMapped[msg.messageorigin_AsJOSN.type]?.renderForReply === 'function'
? whatsappMsgTypeMapped[msg.messageorigin_AsJOSN.type].renderForReply(msg.messageorigin_AsJOSN) ? whatsappMsgTypeMapped[msg.messageorigin_AsJOSN.type].renderForReply(msg.messageorigin_AsJOSN)
: {}), : {}),
titleColor: '#53bdeb', // "#128c7e", // todo: 原始消息的方向 titleColor: msg.messageorigin_AsJOSN?.customerProfile?.name ? '#a791ff' : "#128c7e",
// titleColor: msg.messageorigin_direction === 'inbound' ? '#a791ff' : "#128c7e",
}, },
origin: msg.messageorigin_AsJOSN, origin: msg.messageorigin_AsJOSN,
}), }),

@ -16,6 +16,7 @@ const initialConversationState = {
// websocketRetrytimes: null, // websocketRetrytimes: null,
errors: [], // 错误信息 errors: [], // 错误信息
initialState: false,
// templates: [], // templates: [],
@ -26,7 +27,6 @@ const initialConversationState = {
// referenceMsg: {}, // referenceMsg: {},
}; };
olog('initialConversationState');
export const templatesSlice = (set) => ({ export const templatesSlice = (set) => ({
templates: [], templates: [],
@ -167,8 +167,11 @@ export const conversationSlice = (set, get) => ({
}); });
export const messageSlice = (set, get) => ({ export const messageSlice = (set, get) => ({
msgListLoading: false,
activeConversations: {}, activeConversations: {},
setMsgLoading: (msgListLoading) => set({ msgListLoading }),
receivedMessageList: (conversationid, msgList) => set((state) => ({ receivedMessageList: (conversationid, msgList) => set((state) => ({
msgListLoading: false,
activeConversations: { ...state.activeConversations, [String(conversationid)]: msgList } activeConversations: { ...state.activeConversations, [String(conversationid)]: msgList }
})), })),
updateMessageItem: (message) => { // msgUpdate updateMessageItem: (message) => { // msgUpdate
@ -250,18 +253,20 @@ export const useConversationStore = create(devtools((set, get) => ({
// state actions // state actions
addError: (error) => set((state) => ({ errors: [...state.errors, error] })), addError: (error) => set((state) => ({ errors: [...state.errors, error] })),
setInitial: (v) => set({ initialState: v }),
// side effects // side effects
fetchInitialData: async (userId) => { fetchInitialData: async (userId) => {
olog('fetch init'); const { addToConversationList, setTemplates, setInitial } = get();
const { addToConversationList, setTemplates } = get();
const conversationsList = await fetchConversationsList({ opisn: userId }); const conversationsList = await fetchConversationsList({ opisn: userId });
addToConversationList(conversationsList); addToConversationList(conversationsList);
const templates = await fetchTemplates(); const templates = await fetchTemplates();
setTemplates(templates); setTemplates(templates);
setInitial(true);
}, },
}))); })));
// window.store = useConversationStore; // debug:
export default useConversationStore; export default useConversationStore;

@ -1,6 +1,6 @@
import { useEffect, useState } from 'react'; import { useEffect, useState } from 'react';
import { Layout, Spin, Button } from 'antd'; import { Layout, Spin, Button } from 'antd';
import { RightCircleOutlined, RightOutlined, MenuFoldOutlined, MenuUnfoldOutlined } from '@ant-design/icons'; import { RightCircleOutlined, RightOutlined, ReloadOutlined, MenuFoldOutlined, MenuUnfoldOutlined } from '@ant-design/icons';
// import { useParams, useNavigate } from 'react-router-dom'; // import { useParams, useNavigate } from 'react-router-dom';
import MessagesHeader from './Components/MessagesHeader'; import MessagesHeader from './Components/MessagesHeader';
import Messages from './Components/Messages'; import Messages from './Components/Messages';
@ -52,9 +52,10 @@ const ChatWindow = () => {
<Content style={{ maxHeight: 'calc(100vh - 198px)', height: 'calc(100vh - 198px)' }}> <Content style={{ maxHeight: 'calc(100vh - 198px)', height: 'calc(100vh - 198px)' }}>
<Layout className='h-full'> <Layout className='h-full'>
<Header className='ant-layout-sider-light ant-card h-auto flex justify-between items-center'> <Header className='ant-layout-sider-light ant-card h-auto flex justify-between gap-1 items-center'>
<Button type='text' icon={collapsedLeft ? <MenuUnfoldOutlined /> : <MenuFoldOutlined />} onClick={() => setCollapsedLeft(!collapsedLeft)} className=' rounded-none rounded-l' /> <Button type='text' icon={collapsedLeft ? <MenuUnfoldOutlined /> : <MenuFoldOutlined />} onClick={() => setCollapsedLeft(!collapsedLeft)} className=' rounded-none rounded-l' />
<MessagesHeader /> <MessagesHeader />
{/* <Button type='text' icon={<ReloadOutlined />} onClick={() => setCollapsedRight(!collapsedRight)} className='' title='最新消息记录' /> */}
<Button type='text' icon={collapsedRight ? <MenuFoldOutlined /> : <MenuUnfoldOutlined />} onClick={() => setCollapsedRight(!collapsedRight)} className=' rounded-none rounded-r' /> <Button type='text' icon={collapsedRight ? <MenuFoldOutlined /> : <MenuUnfoldOutlined />} onClick={() => setCollapsedRight(!collapsedRight)} className=' rounded-none rounded-r' />
</Header> </Header>
<Content className="flex-grow bg-whatsapp-bg" > <Content className="flex-grow bg-whatsapp-bg" >

@ -3,11 +3,7 @@ import { useParams, useNavigate, useLocation } from 'react-router-dom';
import { Button, Dropdown } from 'antd'; import { Button, Dropdown } from 'antd';
import { MoreOutlined } from '@ant-design/icons'; import { MoreOutlined } from '@ant-design/icons';
import { useAuthContext } from '@/stores/AuthContext'; import { useAuthContext } from '@/stores/AuthContext';
import { import { fetchOrderConversationsList, fetchConversationItemClose, fetchMessages } from '@/actions/ConversationActions';
fetchOrderConversationsList,
fetchConversationItemClose,
fetchMessages,
} from '@/actions/ConversationActions';
import { ChatList, } from 'react-chat-elements'; import { ChatList, } from 'react-chat-elements';
import { isEmpty } from '@/utils/utils'; import { isEmpty } from '@/utils/utils';
import useConversationStore from '@/stores/ConversationStore'; import useConversationStore from '@/stores/ConversationStore';
@ -50,7 +46,7 @@ const Conversations = () => {
const navigate = useNavigate(); const navigate = useNavigate();
const { loginUser } = useAuthContext(); const { loginUser } = useAuthContext();
const { userId } = loginUser; const { userId } = loginUser;
const { activeConversations, currentConversation, conversationsList, addToConversationList, setCurrentConversation, receivedMessageList, } = useConversationStore(); const { initialState, activeConversations, currentConversation, conversationsList, addToConversationList, setCurrentConversation, receivedMessageList, setMsgLoading } = useConversationStore();
const [chatlist, setChatlist] = useState([]); const [chatlist, setChatlist] = useState([]);
useEffect(() => { useEffect(() => {
setChatlist( setChatlist(
@ -80,12 +76,12 @@ const Conversations = () => {
const [shouldFetchCList, setShouldFetchCList] = useState(true); const [shouldFetchCList, setShouldFetchCList] = useState(true);
useEffect(() => { useEffect(() => {
if (order_sn && shouldFetchCList) { if (order_sn && shouldFetchCList && initialState) {
getOrderConversationList(order_sn); getOrderConversationList(order_sn);
} }
return () => {}; return () => {};
}, [order_sn, shouldFetchCList]); }, [order_sn, shouldFetchCList, initialState]);
const getOrderConversationList = async (colisn) => { const getOrderConversationList = async (colisn) => {
const { whatsapp_phone_number } = switchToC; const { whatsapp_phone_number } = switchToC;
@ -93,19 +89,26 @@ const Conversations = () => {
const data = await fetchOrderConversationsList({ opisn: userId, colisn: colisn, whatsappid: whatsappID }); const data = await fetchOrderConversationsList({ opisn: userId, colisn: colisn, whatsappid: whatsappID });
if (!isEmpty(data)) { if (!isEmpty(data)) {
addToConversationList(data); addToConversationList(data);
const ifCurrent = data.findIndex((item) => item.sn === currentConversation.sn); }
switchConversation(data[ifCurrent === -1 ? 0 : ifCurrent]); // const ifCurrent = data.findIndex((item) => item.sn === currentConversation.sn);
const ifCurrent = conversationsList.findIndex((item) => item.coli_sn === Number(colisn));
if (ifCurrent !== -1) {
switchConversation(conversationsList[ifCurrent === -1 ? 0 : ifCurrent]);
} else { } else {
// reset chat window // reset chat window
setCurrentConversation({ sn: '', customer_name: '', coli_sn: order_sn }); setCurrentConversation({ sn: '', customer_name: '', coli_sn: order_sn });
return false; return false;
} }
}; };
const getMessages = async (item) => {
setMsgLoading(true);
const data = await fetchMessages({ opisn: userId, whatsappid: item.whatsapp_phone_number });
receivedMessageList(item.sn, data);
};
const switchConversation = async (item) => { const switchConversation = async (item) => {
const messagesList = activeConversations[`${item.sn}`] || []; const messagesList = activeConversations[`${item.sn}`] || [];
if (isEmpty(messagesList)) { if (messagesList.length < 20) {
const data = await fetchMessages({ opisn: userId, whatsappid: item.whatsapp_phone_number }); await getMessages(item);
receivedMessageList(item.sn, data);
} }
if (String(item.sn) === String(currentConversation.sn)) { if (String(item.sn) === String(currentConversation.sn)) {
return false; return false;

@ -71,7 +71,8 @@ const InputBox = () => {
<div> <div>
{referenceMsg.id && ( {referenceMsg.id && (
<Flex justify='space-between' className='reply-to bg-gray-100 p-1 rounded-none text-slate-500'> <Flex justify='space-between' className='reply-to bg-gray-100 p-1 rounded-none text-slate-500'>
<div className=' border-l-3 border-y-0 border-r-0 border-slate-300 border-solid pl-2 pr-1 py-1'>{referenceMsg.text}</div> <div className=' border-l-3 border-y-0 border-r-0 border-slate-300 border-solid pl-2 pr-1 py-1'>
<span className=' text-primary pr-1 italic'>{referenceMsg.senderName}</span>{referenceMsg.text}</div>
<Button type='text' title='取消引用' className=' rounded-none text-slate-500' icon={<CloseCircleOutlined />} size={'middle'} onClick={() => (setReferenceMsg({}))} /> <Button type='text' title='取消引用' className=' rounded-none text-slate-500' icon={<CloseCircleOutlined />} size={'middle'} onClick={() => (setReferenceMsg({}))} />
</Flex> </Flex>
)} )}

@ -1,11 +1,11 @@
import { useEffect, useState, useRef, useMemo } from 'react'; import { useEffect, useState, useRef, useMemo } from 'react';
import { Image, Alert } from 'antd'; import { Image, Spin } from 'antd';
import { MessageBox } from 'react-chat-elements'; import { MessageBox } from 'react-chat-elements';
import useConversationStore from '@/stores/ConversationStore'; import useConversationStore from '@/stores/ConversationStore';
import { useShallow } from 'zustand/react/shallow'; import { useShallow } from 'zustand/react/shallow';
const Messages = () => { const Messages = () => {
const { currentConversation, setReferenceMsg } = useConversationStore(); const { currentConversation, setReferenceMsg, msgListLoading, } = useConversationStore();
const activeMessages = useConversationStore(useShallow((state) => (currentConversation.sn ? state.activeConversations[currentConversation.sn] : []))); const activeMessages = useConversationStore(useShallow((state) => (currentConversation.sn ? state.activeConversations[currentConversation.sn] : [])));
const messagesList = useMemo( const messagesList = useMemo(
@ -50,11 +50,13 @@ const Messages = () => {
return ( return (
<div> <div>
<Spin spinning={msgListLoading} tip={'正在读取...'} wrapperClassName='pt-8 ' >
{messagesList.map((message, index) => ( {messagesList.map((message, index) => (
<MessageBox key={message.key} {...message} onReplyClick={() => setReferenceMsg(message)} onOpen={() => handlePreview(message)} /> <MessageBox key={message.key} {...message} onReplyClick={() => setReferenceMsg(message)} onOpen={() => handlePreview(message)} />
))} ))}
<Image src={previewSrc} preview={{ visible: previewVisible, src: previewSrc, onClose: onPreviewClose }} /> <Image src={previewSrc} preview={{ visible: previewVisible, src: previewSrc, onClose: onPreviewClose }} />
<div ref={messagesEndRef}></div> <div ref={messagesEndRef}></div>
</Spin>
</div> </div>
); );
}; };

Loading…
Cancel
Save