显示错误码;解决订单状态设置更新;修改store 取值;消息样式;新消息闪烁提醒;消息解析 链接和表情;WhatsApp号码判断

dev/mobile
Lei OT 2 years ago
parent dd19a3584c
commit c81e807790

@ -20,7 +20,7 @@ export const fetchConversationsList = async (params) => {
export const fetchMessages = async (params) => {
const { result } = await fetchJSON(`${API_HOST}/getcusmessages`, params);
return parseRenderMessageList(result);
return parseRenderMessageList(result || []);
}
export const fetchCustomerProfile = async (colisn) => {

@ -15,10 +15,11 @@ export const replaceTemplateString = (str, replacements) => {
}
export const autoLinkText = (text) => {
let regex = /(https?:\/\/[^\s]+)/g;
return text;
// let regex = /(https?:\/\/[^\s]+)/g;
let newText = text.replace(regex, '<a href="$1" target="_blank">$1</a>');
return newText;
// let newText = text.replace(regex, '<a href="$1" target="_blank">$1</a>');
// return newText;
}
/**
*
@ -298,7 +299,7 @@ export const parseRenderMessageItem = (msg) => {
whatsapp_name: msg?.customerProfile?.name || '',
whatsapp_phone_number: msg.from,
whatsapp_msg_type: msg.type,
...((isEmpty(msg.context) && isEmpty(msg.reaction)) || msg.context.forwarded === true
...((isEmpty(msg.context) && isEmpty(msg.reaction)) || msg.context?.forwarded === true
? {}
: {
reply: {
@ -319,7 +320,7 @@ export const parseRenderMessageItem = (msg) => {
* 从数据库读取的记录
*/
export const parseRenderMessageList = (messages, conversationid = null) => {
return messages.map((msg) => {
return messages.map((msg, i) => {
const msgContent = msg.msgtext_AsJOSN;
msgContent.template = msg.msgtype === 'template' ? { ...msgContent.template, ...msg.template_AsJOSN } : {};
const msgType = msgContent.type;
@ -341,14 +342,15 @@ export const parseRenderMessageList = (messages, conversationid = null) => {
dateString: msgStatusRenderMapped[msgContent?.status || 'failed'] === 'failed' ? `发送失败 ${whatsappError?.[msgContent.errorCode] || msgContent.errorMessage}` : '',
}
: {}),
...(isEmpty(msg.messageorigin_AsJOSN) && isEmpty(msgContent.context)
...((isEmpty(msg.messageorigin_AsJOSN) && isEmpty(msgContent.context))
// ...((isEmpty(msg.messageorigin_AsJOSN) || isEmpty(msgContent.context))
? {}
: {
reply: {
message: msg.messageorigin_AsJOSN.text?.body || msg.messageorigin_AsJOSN.text,
title: msg.messageorigin_AsJOSN?.customerProfile?.name || msg.messageorigin_AsJOSN.senderName || 'me',
...(typeof whatsappMsgTypeMapped[msg.messageorigin_AsJOSN.type]?.renderForReply === 'function'
? whatsappMsgTypeMapped[msg.messageorigin_AsJOSN.type].renderForReply(msg.messageorigin_AsJOSN)
message: msg.messageorigin_AsJOSN?.text?.body || msg.messageorigin_AsJOSN?.text,
title: msg.messageorigin_AsJOSN?.customerProfile?.name || msg.messageorigin_AsJOSN?.senderName || 'me',
...(typeof whatsappMsgTypeMapped[msg.messageorigin_AsJOSN?.type]?.renderForReply === 'function'
? whatsappMsgTypeMapped[msg.messageorigin_AsJOSN?.type].renderForReply(msg.messageorigin_AsJOSN)
: {}),
// titleColor: msg.messageorigin_AsJOSN?.customerProfile?.name ? '#a791ff' : "#128c7e",
titleColor: msg.messageorigin_direction === 'inbound' ? '#a791ff' : "#128c7e",
@ -362,9 +364,9 @@ export const parseRenderMessageList = (messages, conversationid = null) => {
});
};
export const whatsappError = {
'131026': '消息无法投递. [未注册/使用旧版/未同意政策]',
'131047': '会话超过24小时.',
'131053': '文件上传失败.',
'131048': '账户被风控.', // 消息发送太多, 达到垃圾数量限制
'131031': '账户已锁定.',
'131026': '[131026] 消息无法投递(未注册/使用旧版/未同意政策).',
'131047': '[131047] 会话超过24小时.',
'131053': '[131053] 文件上传失败.',
'131048': '[131048] 账户被风控.', // 消息发送太多, 达到垃圾数量限制
'131031': '[131031] 账户已锁定.',
};

@ -45,7 +45,7 @@ const websocketSlice = (set, get) => ({
setWebsocketRetrytimes: (retrytimes) => set({ websocketRetrytimes: retrytimes, websocketRetrying: retrytimes > 0 }),
connectWebsocket: (userId) => {
const { setWebsocket, setWebsocketOpened, setWebsocketRetrytimes, addError, handleMessage } = get();
const { setWebsocket, setWebsocketOpened, setWebsocketRetrytimes, addError, handleMessage, activeConversations } = get();
const realtimeAPI = new RealTimeAPI(
{
@ -56,7 +56,15 @@ const websocketSlice = (set, get) => ({
setWebsocketOpened(true);
setWebsocketRetrytimes(0);
},
() => setWebsocketOpened(false),
() => {
setWebsocketOpened(false)
const newMsgList = Object.keys(activeConversations).reduce((acc, key) => {
const newMsgList = activeConversations[key].slice(-10);
acc[key] = newMsgList;
return acc;
}, {});
set({ activeConversations: newMsgList });
},
(n) => setWebsocketRetrytimes(n)
);
@ -108,6 +116,8 @@ const websocketSlice = (set, get) => ({
if (permission === 'granted') {
const notification = new Notification(`${msgRender.senderName}`, {
body: msgRender?.text || `[ ${msgRender.type} ]`,
requireInteraction: true, // 设置手动关闭
tag: 'global-sales-notification', // 通知ID同类通知建议设置相同ID避免通知过多遮挡桌面
...(msgRender.type === 'photo' ? { image: msgRender.data.uri } : {}),
});
notification.onclick = function () {
@ -149,7 +159,8 @@ const conversationSlice = (set, get) => ({
return set((state) => ({
conversationsList: [...newConversations, ...state.conversationsList],
activeConversations: { ...activeConversations, ...newConversationsMapped }
activeConversations: { ...activeConversations, ...newConversationsMapped },
totalNotify: state.totalNotify + newConversations.map(ele => ele.unread_msg_count).reduce((acc, cur) => acc + (cur || 0), 0),
}));
},
delConversationitem: (conversation) => {
@ -158,15 +169,15 @@ const conversationSlice = (set, get) => ({
const targetIndex = conversationsList.findIndex((ele) => String(ele.sn) === String(targetId));
conversationsList.splice(targetIndex, 1);
return set((state) => ({
return set({
conversationsList: [...conversationsList],
activeConversations: { ...activeConversations, [`${targetId}`]: [] },
currentConversation: {},
}));
});
},
setCurrentConversation: (conversation) => {
// 清空未读
const { conversationsList } = get();
const { conversationsList, totalNotify } = get();
const targetId = conversation.sn;
const targetIndex = conversationsList.findIndex((ele) => String(ele.sn) === String(targetId));
targetIndex !== -1 ? conversationsList.splice(targetIndex, 1, {
@ -174,11 +185,12 @@ const conversationSlice = (set, get) => ({
unread_msg_count: 0,
}) : null;
return set({ currentConversation: conversation, referenceMsg: {}, conversationsList: [...conversationsList] });
return set({ totalNotify: totalNotify - (conversation.unread_msg_count || 0), currentConversation: conversation, referenceMsg: {}, conversationsList: [...conversationsList] });
},
});
const messageSlice = (set, get) => ({
totalNotify: 0,
msgListLoading: false,
activeConversations: {},
setMsgLoading: (msgListLoading) => set({ msgListLoading }),
@ -216,21 +228,21 @@ const messageSlice = (set, get) => ({
// });
// }
return set((state) => ({
return set({
activeConversations: { ...activeConversations, [String(targetId)]: targetMsgs },
conversationsList: [...conversationsList],
}));
// conversationsList: [...conversationsList],
});
},
sentOrReceivedNewMessage: (targetId, message) => { // msgRender:
const { activeConversations, conversationsList, currentConversation } = get();
const { activeConversations, conversationsList, currentConversation, totalNotify } = get();
const targetMsgs = activeConversations[String(targetId)] || [];
const targetIndex = conversationsList.findIndex((ele) => String(ele.sn) === String(targetId));
const updateTime = message.type !== 'system' && message.sender !== 'me' ? message.date : null;
const lastReceivedTime = message.type !== 'system' && message.sender !== 'me' ? message.date : null;
const newConversation =
targetId !== -1
? {
...conversationsList[targetIndex],
last_received_time: updateTime || conversationsList[targetIndex].last_received_time,
last_received_time: lastReceivedTime || conversationsList[targetIndex].last_received_time,
unread_msg_count:
String(targetId) !== String(currentConversation.sn) && message.sender !== 'me'
? conversationsList[targetIndex].unread_msg_count + 1
@ -244,14 +256,15 @@ const messageSlice = (set, get) => ({
};
conversationsList.splice(targetIndex, 1);
conversationsList.unshift(newConversation);
return set((state) => ({
return set({
totalNotify: totalNotify+newConversation.unread_msg_count,
activeConversations: { ...activeConversations, [String(targetId)]: [...targetMsgs, message] },
conversationsList: [...conversationsList],
currentConversation: {
...currentConversation,
last_received_time: String(targetId) === String(currentConversation.sn) ? updateTime : currentConversation.last_received_time,
...(String(targetId) === String(currentConversation.sn) ? { last_received_time: message.date } : {}),
},
}));
});
},
});

@ -3,10 +3,10 @@ import useAuthStore from '@/stores/AuthStore'
import useConversationStore from '@/stores/ConversationStore'
import { useThemeContext } from '@/stores/ThemeContext'
import { DownOutlined } from '@ant-design/icons'
import { App as AntApp, Avatar, Col, ConfigProvider, Dropdown, Empty, Layout, Menu, Row, Space, Typography, theme } from 'antd'
import { App as AntApp, Avatar, Col, ConfigProvider, Dropdown, Empty, Layout, Menu, Row, Space, Typography, theme, Badge } from 'antd'
import zhLocale from 'antd/locale/zh_CN'
import 'dayjs/locale/zh-cn'
import { useEffect } from 'react'
import { useEffect, useState } from 'react'
import { Link, NavLink, Outlet, useHref, useNavigate } from 'react-router-dom'
import '@/assets/App.css'
@ -22,7 +22,7 @@ function AuthApp() {
const { colorPrimary, borderRadius } = useThemeContext()
const { loginUser } = useAuthStore()
const href = useHref()
useEffect(() => {
@ -32,7 +32,7 @@ function AuthApp() {
}
}, [href])
const totalNotify = useConversationStore((state) => state.totalNotify);
useEffect(() => {
if (loginUser.userId > 0) {
useConversationStore.getState().connectWebsocket(loginUser.userId);
@ -54,6 +54,44 @@ function AuthApp() {
token: { colorBgContainer },
} = theme.useToken()
// Flicker title when new message received
const [isTitleVisible, setIsTitleVisible] = useState(true);
useEffect(() => {
let interval;
if (totalNotify > 0) {
interval = setInterval(() => {
document.title = isTitleVisible ? `✉🔔🔥【${totalNotify}条新消息】` : '聊天式销售平台';
setIsTitleVisible(!isTitleVisible);
}, 600);
} else {
document.title = '聊天式销售平台';
}
return () => clearInterval(interval);
}, [totalNotify, isTitleVisible]);
// Display browser notification and change favicon when new message received
// useEffect(() => {
// if (hasNewMessage) {
// if (Notification.permission === "granted") {
// new Notification("New messages received!", {
// body: "You have new messages.",
// icon: "path-to-your-icon.png",
// });
// } else if (Notification.permission !== "denied") {
// Notification.requestPermission().then(permission => {
// if (permission === "granted") {
// new Notification("New messages received!", {
// body: "You have new messages.",
// icon: "path-to-your-icon.png",
// });
// }
// });
// }
// setFavicon('path-to-your-new-favicon.ico');
// }
// }, [hasNewMessage]);
return (
<ConfigProvider
theme={{
@ -85,7 +123,13 @@ function AuthApp() {
selectedKeys={[defaultPath]}
items={[
{ key: '/order/follow', label: <Link to='/order/follow'>订单跟踪</Link> },
{ key: '/order/chat', label: <Link to='/order/chat'>在线聊天</Link> },
{ key: '/order/chat', label: <Link to='/order/chat'>在线聊天
<Badge
count={totalNotify}
style={{
backgroundColor: '#52c41a',
}}
/></Link> },
{ key: '/chat/history', label: <Link to='/chat/history'>聊天历史</Link> },
]}
/>

@ -16,19 +16,16 @@ const Conversations = () => {
const { coli_guest_WhatsApp } = orderRow || {};
const { order_sn } = useParams();
const navigate = useNavigate();
const { loginUser } = useAuthStore();
const { userId } = loginUser;
const {
initialState,
activeConversations,
currentConversation,
conversationsList,
addToConversationList,
delConversationitem,
setCurrentConversation,
receivedMessageList,
setMsgLoading,
} = useConversationStore();
const userId = useAuthStore(state => state.loginUser.userId);
const initialState = useConversationStore((state) => state.initialState);
const activeConversations = useConversationStore((state) => state.activeConversations);
const currentConversation = useConversationStore((state) => state.currentConversation);
const conversationsList = useConversationStore((state) => state.conversationsList);
const addToConversationList = useConversationStore((state) => state.addToConversationList);
const delConversationitem = useConversationStore((state) => state.delConversationitem);
const setCurrentConversation = useConversationStore((state) => state.setCurrentConversation);
const receivedMessageList = useConversationStore((state) => state.receivedMessageList);
const setMsgLoading = useConversationStore((state) => state.setMsgLoading);
const [switchToC, setSwitchToC] = useState({});
const [shouldFetchCList, setShouldFetchCList] = useState(true);
@ -43,14 +40,16 @@ const Conversations = () => {
const getOrderConversationList = async (colisn) => {
const { whatsapp_phone_number } = switchToC;
const whatsappID = coli_guest_WhatsApp || whatsapp_phone_number || '';
const data = await fetchOrderConversationsList({ opisn: userId, colisn: colisn, whatsappid: whatsappID });
if (!isEmpty(data)) {
addToConversationList(data);
let findCurrent = -1; // conversationsList.findIndex((item) => item.coli_sn === Number(colisn));
if (!isEmpty(whatsappID)) {
const data = await fetchOrderConversationsList({ opisn: userId, colisn: colisn, whatsappid: whatsappID });
if (!isEmpty(data)) {
addToConversationList(data);
}
findCurrent = conversationsList.findIndex((item) => item.coli_sn === Number(colisn)); // data.findIndex((item) => item.sn === currentConversation.sn);
}
let ifCurrent = data.findIndex((item) => item.sn === currentConversation.sn);
ifCurrent = ifCurrent !== -1 ? ifCurrent : conversationsList.findIndex((item) => item.coli_sn === Number(colisn));
if (ifCurrent !== -1) {
switchConversation(conversationsList[ifCurrent === -1 ? 0 : ifCurrent]);
if (findCurrent !== -1) {
switchConversation(conversationsList[findCurrent]);
} else {
// reset chat window
setCurrentConversation({ sn: '', customer_name: '', coli_sn: order_sn });

@ -15,7 +15,7 @@ const InputTemplate = ({ disabled = false, inputEmoji }) => {
overlayClassName='p-0'
placement={'right'}
overlayInnerStyle={{ padding: 0, borderRadius: '8px' }}
fresh
// fresh
content={<EmojiPicker skinTonesDisabled={true} emojiStyle='facebook' onEmojiClick={handlePickEmoji} />}
// title='😀'
trigger='click'

@ -43,7 +43,10 @@ const mockGetOSSData = () => ({
});
const ImageUpload = ({ disabled, invokeSendMessage }) => {
const { currentConversation, setComplexMsg, complexMsg } = useConversationStore();
const currentConversation = useConversationStore(state => state.currentConversation);
const setComplexMsg = useConversationStore(state => state.setComplexMsg);
const complexMsg = useConversationStore(state => state.complexMsg);
const [uploading, setUploading] = useState(false);
const [OSSData, setOSSData] = useState();

@ -24,8 +24,9 @@ const splitTemplate = (template) => {
const InputTemplate = ({ disabled = false, invokeSendMessage }) => {
const searchInputRef = useRef(null);
const { notification } = App.useApp();
const { loginUser } = useAuthStore()
const { currentConversation, templates } = useConversationStore();
const loginUser = useAuthStore(state => state.loginUser);
const currentConversation = useConversationStore(state => state.currentConversation);
const templates = useConversationStore(state => state.templates);
// : customer, agent
const valueMapped = { ...cloneDeep(currentConversation), ...objectMapper(loginUser, { username: [{ key: 'agent_name' }, { key: 'your_name' }] }) };
useEffect(() => {

@ -26,10 +26,16 @@ import InputImageUpload from './Input/ImageUpload';
import dayjs from 'dayjs';
const InputComposer = () => {
const {
loginUser: { userId },
} = useAuthStore();
const { websocket, websocketOpened, currentConversation, referenceMsg, setReferenceMsg, complexMsg, setComplexMsg, sentOrReceivedNewMessage } = useConversationStore();
const userId = useAuthStore(state => state.loginUser.userId);
const websocket = useConversationStore(state => state.websocket);
const websocketOpened = useConversationStore(state => state.websocketOpened);
const currentConversation = useConversationStore(state => state.currentConversation);
const referenceMsg = useConversationStore(state => state.referenceMsg);
const setReferenceMsg = useConversationStore(state => state.setReferenceMsg);
const complexMsg = useConversationStore(state => state.complexMsg);
const setComplexMsg = useConversationStore(state => state.setComplexMsg);
const sentOrReceivedNewMessage = useConversationStore(state => state.sentOrReceivedNewMessage);
const talkabled = !isEmpty(currentConversation.sn) && websocketOpened;
const gt24h = currentConversation.last_received_time ? dayjs().diff(dayjs(currentConversation.last_received_time), 'hour') > 24 : true;
const textabled = talkabled && !gt24h;
@ -84,7 +90,7 @@ const InputComposer = () => {
<div>
{referenceMsg.id && (
<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'>
<div className='referrer-msg 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.originText}
</div>
@ -122,7 +128,7 @@ const InputComposer = () => {
/>
<Flex justify={'space-between'} className=' bg-gray-200 p-1 rounded-b'>
<Flex gap={4} className='*:text-primary *:rounded-none'>
<InputTemplate key='templates' disabled={textabled} invokeSendMessage={invokeSendMessage} />
<InputTemplate key='templates' disabled={!talkabled} invokeSendMessage={invokeSendMessage} />
<InputEmoji key='emoji' disabled={!textabled} inputEmoji={(s) => setTextContent(`${textContent}${s}`)} />
{/* <InputImageUpload key={'addNewPic'} disabled={!textabled} invokeSendMessage={invokeSendMessage} /> */}
{/* <Button type='text' className='' icon={<YoutubeOutlined />} size={'middle'} />

@ -1,34 +1,18 @@
import { useEffect, useState, useRef, useMemo } from 'react';
import { useEffect, useState, useRef, useMemo, memo } from 'react';
import { Image, Spin, Dropdown } from 'antd';
import { DownOutlined } from '@ant-design/icons';
import { MessageBox } from 'react-chat-elements';
import useConversationStore from '@/stores/ConversationStore';
import { useShallow } from 'zustand/react/shallow';
import { Emoji } from 'emoji-picker-react';
import { olog } from '@/utils/utils';
const Messages = () => {
const { currentConversation, setReferenceMsg, msgListLoading } = useConversationStore();
const activeMessages = useConversationStore(useShallow((state) => (currentConversation.sn ? state.activeConversations[currentConversation.sn] : [])));
const messagesList = useMemo(
() =>
(activeMessages || []).map((message) => ({
...message,
key: message.id,
position: message.sender === 'me' ? 'right' : 'left',
...(message.sender === 'me'
? {
styles: { backgroundColor: '#ccd4ae' },
notchStyle: { fill: '#ccd4ae' },
replyButton: ['text'].includes(message.whatsapp_msg_type) && message.status !== 'failed' ? true : false,
className: 'whatsappme-container whitespace-pre-wrap',
}
: {
replyButton: ['text'].includes(message.whatsapp_msg_type) ? true : false,
}),
})),
[activeMessages]
);
// console.log('messagesList----------------------------------------------------', messagesList);
const currentConversation = useConversationStore(useShallow((state) => state.currentConversation));
const setReferenceMsg = useConversationStore(useShallow((state) => state.setReferenceMsg));
const msgListLoading = useConversationStore(useShallow((state) => state.msgListLoading));
const activeMessages = useConversationStore(useShallow((state) => (state.currentConversation.sn ? state.activeConversations[state.currentConversation.sn] : [])));
olog('invoke msg list');
const messagesEndRef = useRef(null);
useEffect(() => {
@ -49,12 +33,39 @@ const Messages = () => {
setPreviewSrc(msg.data.uri);
};
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}\uFE0F?|\b\d+\b)/gu);
return (
<>
{(parts || []).map((part, index) => {
// if (/\p{Emoji}\uFE0F?/u.test(part)) {
if (/\p{Emoji_Presentation}/u.test(part)) {
const code = [...part].map((e) => e.codePointAt(0).toString(16)).join(`-`);
return <Emoji key={`${part}${index}${code}`} unified={code} size={24} emojiStyle='facebook' />;
} else
if (/https?:\/\/[\S]+/gi.test(part)) {
return (
<a href={part} target='_blank' key={`${part}${index}`} rel='noreferrer'>
{part}
</a>
);
} else if (part.trim() !== '') {
return <span key={`${part}${index}`}>{part}</span>;
} else {
return <span key={`${part}${index}`}>{part}</span>;
}
})}
</>
);
});
return (
<div>
<Spin spinning={msgListLoading} tip={'正在读取...'} wrapperClassName='pt-8 '>
{messagesList.map((message, index) => (
{activeMessages.map((message, index) => (
<Dropdown
key={message.key}
key={message.id}
menu={{
items: [{ label: '回复', key: 'reply', disabled: !['text'].includes(message.whatsapp_msg_type) }],
onClick: ({ key, domEvent }) => {
@ -68,14 +79,24 @@ const Messages = () => {
}
},
}}
trigger={['contextMenu']}
>
trigger={['contextMenu']}>
<MessageBox
key={message.key}
key={message.id}
{...message}
position={message.sender === 'me' ? 'right' : 'left'}
onReplyClick={() => setReferenceMsg(message)}
onOpen={() => handlePreview(message)}
{...(message.type === 'text' ? { text: <div dangerouslySetInnerHTML={{ __html: message.text }}></div> } : {})}
text={<RenderText str={message?.text || ''} />}
{...(message.sender === 'me'
? {
styles: { backgroundColor: '#ccd4ae' },
notchStyle: { fill: '#ccd4ae' },
replyButton: ['text'].includes(message.whatsapp_msg_type) && message.status !== 'failed' ? true : false,
className: 'whatsappme-container whitespace-pre-wrap',
}
: {
replyButton: ['text'].includes(message.whatsapp_msg_type) ? true : false,
})}
/>
</Dropdown>
))}

@ -5,8 +5,13 @@ import { ReloadOutlined, ApiOutlined } from '@ant-design/icons';
import { LoadingOutlined } from '@ant-design/icons';
const MessagesHeader = () => {
const { loginUser: { userId } } = useAuthStore()
const {websocketOpened, websocketRetrying, websocketRetrytimes, currentConversation, connectWebsocket} = useConversationStore();
const userId = useAuthStore(state => state.loginUser.userId);
const websocketOpened = useConversationStore(state => state.websocketOpened);
const websocketRetrying = useConversationStore(state => state.websocketRetrying);
const websocketRetrytimes = useConversationStore(state => state.websocketRetrytimes);
const currentConversation = useConversationStore(state => state.currentConversation);
const connectWebsocket = useConversationStore(state => state.connectWebsocket);
return (
<>
{websocketOpened === false && (
@ -15,9 +20,11 @@ const MessagesHeader = () => {
message='断开连接'
banner
action={
websocketRetrytimes === -1 ? <Tooltip key={'connect'} title='点击重试'>
<Button key={'connect'} type='text' icon={<ApiOutlined />} onClick={() => connectWebsocket(userId)} className=' text-blue-500' />
</Tooltip> : null
websocketRetrytimes === -1 ? (
<Tooltip key={'connect'} title='点击重试'>
<Button key={'connect'} type='text' icon={<ApiOutlined />} onClick={() => connectWebsocket(userId)} className=' text-blue-500' />
</Tooltip>
) : null
}
/>
)}
@ -26,8 +33,16 @@ const MessagesHeader = () => {
{/* {currentConversation.customer_name && <Avatar src={`https://api.dicebear.com/7.x/avataaars/svg?seed=${currentConversation.customer_name}`} />} */}
<Flex flex={'1'} justify='space-between'>
<Flex vertical={false} gap={12} justify='space-between'>
<Typography.Text strong>{currentConversation.customer_name}</Typography.Text>
<Typography.Text>{currentConversation.whatsapp_phone_number}</Typography.Text>
{currentConversation.whatsapp_phone_number ? (
<>
<Typography.Text strong>{currentConversation.customer_name}</Typography.Text>
<Typography.Text>{currentConversation.whatsapp_phone_number}</Typography.Text>
</>
) : (
<Typography.Text strong type='danger'>
没有WhatsApp号码
</Typography.Text>
)}
</Flex>
<Flex vertical={true} justify='space-between'>
<Typography.Text>{/* <LocalTimeClock /> <Typography.Text strong>{order?.location} </Typography.Text> */}</Typography.Text>

@ -9,7 +9,7 @@
/** Chat Window */
.chatwindow-wrapper .rce-container-mbox .rce-mbox{
max-width: 400px;
max-width: 500px;
}
.chatwindow-wrapper .rce-citem {
background: transparent;
@ -18,6 +18,9 @@
background: linear-gradient(0deg,#00000014,#0000);
color: #00000073;
}
.chatwindow-wrapper .rce-mbox-text, .chatwindow-wrapper .referrer-msg {
font-family: 'Twemoji Mozilla', 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol', 'Noto Color Emoji', 'EmojiOne Color', 'Android Emoji', sans-serif;
}
.chatwindow-wrapper .rce-mbox-text a{
color: #4f81a1;
}
@ -45,4 +48,6 @@
margin-left: 5px;
justify-content: flex-start;
font-size: 12px;
word-wrap: break-word;
height: 100%;
}

Loading…
Cancel
Save