From d87a8e0a7143c72a5cd3322de282b3641bb4d1a4 Mon Sep 17 00:00:00 2001 From: Lei OT Date: Thu, 1 Feb 2024 15:36:59 +0800 Subject: [PATCH] =?UTF-8?q?=E8=8E=B7=E5=8F=96=E6=B6=88=E6=81=AF=E8=AE=B0?= =?UTF-8?q?=E5=BD=95;=20=E6=A8=A1=E6=9D=BF=E6=B6=88=E6=81=AF:=20body:=20?= =?UTF-8?q?=E5=8F=91=E9=80=81=E5=8F=82=E6=95=B0=E5=A1=AB=E5=85=85=E5=90=8E?= =?UTF-8?q?=E7=9A=84=E6=95=B4=E4=BD=93=E5=86=85=E5=AE=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/actions/ConversationActions.js | 12 +++- src/lib/msgUtils.js | 47 ++++++++++++---- src/reducers/ConversationReducer.js | 7 +++ .../Components/ConversationsList.jsx | 46 +++++++++++----- .../Conversations/Components/InputBox.jsx | 55 ++++++++++++------- 5 files changed, 120 insertions(+), 47 deletions(-) diff --git a/src/actions/ConversationActions.js b/src/actions/ConversationActions.js index 1c155cf..b44fd84 100644 --- a/src/actions/ConversationActions.js +++ b/src/actions/ConversationActions.js @@ -1,6 +1,7 @@ import { groupBy } from '@/utils/utils'; import { fetchJSON, postJSON } from '@/utils/request' +import { parseRenderMessageList } from '@/lib/msgUtils'; const API_HOST = 'https://p9axztuwd7x8a7.mycht.cn/whatsapp_callback'; @@ -78,12 +79,16 @@ export const updateMessageItem = (message) => ({ type: NAME_SPACE + 'UPDATE_SENT_MESSAGE_ITEM', payload: message, }); +export const receivedMessageList = (targetId, data) => ({ + type: NAME_SPACE + 'RECEIVED_MESSAGE_LIST', + payload: { targetId, data }, +}) export const fetchTemplates = async () => { const data = await fetchJSON(`${API_HOST}/listtemplates`); const canUseTemplates = (data?.result?.items || []) .filter((_t) => _t.status !== 'REJECTED') - .map((ele) => ({ ...ele, components: groupBy(ele.components, (_c) => _c.type.toLowerCase()) })); + .map((ele) => ({ ...ele, components_origin: ele.components, components: groupBy(ele.components, (_c) => _c.type.toLowerCase()) })); return canUseTemplates; }; @@ -93,6 +98,11 @@ export const fetchConversationsList = async (opisn) => { return list; }; +export const fetchMessages = async (params) => { + const { result } = await fetchJSON(`${API_HOST}/getcusmessages`, params); + return parseRenderMessageList(result); +} + export const fetchCustomerProfile = async (colisn) => { const { result } = await fetchJSON(`${API_HOST}/getorderinfo`, { colisn }); const data = result?.[0] || {}; diff --git a/src/lib/msgUtils.js b/src/lib/msgUtils.js index 7d51e73..dcd2b7e 100644 --- a/src/lib/msgUtils.js +++ b/src/lib/msgUtils.js @@ -33,8 +33,8 @@ export const sentMsgTypeMapped = { contentToRender: (msg) => { console.log(msg); const templateDataMapped = msg.template?.components ? msg.template.components.reduce((r, v) => ({...r, [v.type]: v}), {}) : null; - const templateParam = (templateDataMapped?.body?.parameters || []).map(e => e.text); - const fillTemplate = templateParam.length ? replaceTemplateString(msg.template_origin.components.body?.[0]?.text || '', templateParam) : (msg.template_origin.components.body?.[0]?.text || ''); + // const templateParam = (templateDataMapped?.body?.parameters || []).map(e => e.text); + // const fillTemplate = templateParam.length ? replaceTemplateString(msg.template_origin.components.body?.[0]?.text || '', templateParam) : (msg.template_origin.components.body?.[0]?.text || ''); // const footer = msg.template_origin.components?.footer?.[0]?.text || ''; return { ...msg, @@ -42,7 +42,7 @@ export const sentMsgTypeMapped = { conversationid: msg.id.split('.')[0], type: 'text', title: msg.template_origin.components.header?.[0]?.text || '', - text: `${fillTemplate}`, // msg.template_origin.components.body?.[0]?.text || '', + text: templateDataMapped?.body?.text || '', // msg.template_origin.components.body?.[0]?.text || '', }; }, }, @@ -116,8 +116,8 @@ export const whatsappMsgTypeMapped = { data: (msg) => ({ id: msg.wamid, text: msg.errorCode ? msg.errorMessage : msg.text.body }), }, text: { - type: (msg) => ({ type: msg.errorCode ? 'system' : 'text' }), - data: (msg) => ({ id: msg.wamid, text: msg.errorCode ? msg.errorMessage : msg.text.body }), + type: 'text', + data: (msg) => ({ id: msg.wamid, text: msg.text.body }), }, image: { type: 'photo', @@ -171,6 +171,14 @@ export const whatsappMsgTypeMapped = { // 'contact-card': 'contact-card', // 'contact-card-with-photo': 'contact-card-with-photo', // 'contact-card-with-photo-and-label': 'contact-card-with-photo-and-label', + template: { + type: 'text', + data: (msg) => { + const templateDataMapped = msg.template?.components ? msg.template.components.reduce((r, v) => ({...r, [v.type]: v}), {}) : null; + console.log(msg.template.name, templateDataMapped); + return { id: msg.wamid, text: templateDataMapped?.body?.parameters?.[0]?.text || '', title: msg.template.name } + }, + }, }; /** * render received msg @@ -189,15 +197,29 @@ export const parseRenderMessageItem = (msg) => { // replyButton: true, }; }; -export const parseRenderMessageList = (messages) => { +/** + * 从数据库读取的记录 + */ +export const parseRenderMessageList = (messages, conversationid = null) => { return messages.map((msg) => { + const msgContent = msg.msgtext_AsJOSN; + const msgType = msgContent.type; + // const parseMethod = msgContent.bizType === 'whatsapp' ? cloneDeep(whatsappMsgTypeMapped) : {}; return { - ...(whatsappMsgTypeMapped?.[msg.type]?.data(msg) || {}), - ...(whatsappMsgTypeMapped?.[msg.type]?.type(msg) || { type: 'text' }), // type: whatsappMsgTypeMapped?.[msg.type]?.type || 'text', - id: msg.id, - sender: msg.from, + ...(whatsappMsgTypeMapped?.[msgType]?.data(msgContent) || {}), + type: msgContent.type, + ...(typeof whatsappMsgTypeMapped[msgType].type === 'function' ? whatsappMsgTypeMapped[msgType].type(msg) : { type: whatsappMsgTypeMapped[msgType].type || 'text' }), + date: msgContent?.sendTime || msg.msgtime || '', + sender: msgContent.from, + ...(msg.msg_direction === 'outbound' + ? { + sender: 'me', + status: msgStatusRenderMapped[msgContent?.status || 'failed'], + dateString: msgStatusRenderMapped[msgContent?.status || 'failed'] === 'failed' ? '发送失败 ❌' : '', + } + : {}), + // conversationid: conversationid, // title: msg.customerProfile.name, - date: msg.sendTime, }; }); }; @@ -206,6 +228,9 @@ export const parseRenderMessageList = (messages) => { * WhatsApp Templates params */ export const whatsappTemplatesParamMapped = { + /** @deprecated */ 'asia_highlights_has_receive_your_inquiry': [['customer_name']], 'hello_from_asia_highlights': [['agent_name']], // todo: + 'hello_from_china_highlights': [['agent_name']], // todo: + 'use_new_whatsapp': [['agent_name']], // todo: }; diff --git a/src/reducers/ConversationReducer.js b/src/reducers/ConversationReducer.js index f16ae21..a5c1595 100644 --- a/src/reducers/ConversationReducer.js +++ b/src/reducers/ConversationReducer.js @@ -76,6 +76,13 @@ const ConversationReducer = (state = initialState, action) => { conversationsList: newConversationList, }; } + case NAME_SPACE + 'RECEIVED_MESSAGE_LIST': { + const { targetId, data } = action.payload; + return { + ...state, + activeConversations: { ...state.activeConversations, [String(targetId)]: data }, + }; + } case NAME_SPACE + 'SENT_NEW_MESSAGE': case NAME_SPACE + 'RECEIVED_NEW_MESSAGE': { const { activeConversations, conversationsList, currentConversation } = state; diff --git a/src/views/Conversations/Components/ConversationsList.jsx b/src/views/Conversations/Components/ConversationsList.jsx index 05c0a71..87f361a 100644 --- a/src/views/Conversations/Components/ConversationsList.jsx +++ b/src/views/Conversations/Components/ConversationsList.jsx @@ -1,26 +1,33 @@ import { useRef, useEffect, useState } from 'react'; -import { useParams, useNavigate } from "react-router-dom"; +import { useParams, useNavigate } from 'react-router-dom'; import { List, Avatar, Flex } from 'antd'; import { useAuthContext } from '@/stores/AuthContext'; import { useConversationState, useConversationDispatch } from '@/stores/ConversationContext'; -import { fetchCustomerProfile, receivedCustomerProfile, setCurrentConversation, addConversationList, postConversationItemClose } from '@/actions/ConversationActions' +import { + fetchCustomerProfile, + receivedCustomerProfile, + setCurrentConversation, + addConversationList, + postConversationItemClose, + fetchMessages, receivedMessageList, +} from '@/actions/ConversationActions'; import { ChatList } from 'react-chat-elements'; import { isEmpty, pick } from '@/utils/utils'; import { v4 as uuid } from 'uuid'; /** * [] */ -const Conversations = (() => { - const { order_sn } = useParams(); +const Conversations = () => { + const { order_sn } = useParams(); const navigate = useNavigate(); const { loginUser } = useAuthContext(); const { userId } = loginUser; - const {conversationsList} = useConversationState(); + const { conversationsList, activeConversations, currentConversation } = useConversationState(); const dispatch = useConversationDispatch(); const [chatlist, setChatlist] = useState([]); useEffect(() => { setChatlist( - (conversationsList).map((item) => ({ + conversationsList.map((item) => ({ ...item, avatar: `https://api.dicebear.com/7.x/avataaars/svg?seed=${item.whatsapp_name.trim() || item.whatsapp_phone_number}`, id: item.sn, @@ -71,8 +78,8 @@ const Conversations = (() => { // 'opi_sn': 354, 'coli_sn': colisn, 'whatsapp_phone_number': data.contact[0].whatsapp_phone_number, - "last_received_time": '', - "last_send_time": '', + 'last_received_time': '', + 'last_send_time': '', 'unread_msg_count': 0, 'whatsapp_name': data.contact[0].name, 'customer_name': data.contact[0].name, @@ -81,12 +88,20 @@ const Conversations = (() => { const newCurrent = pick(newChat, ['sn', 'coli_sn', 'whatsapp_phone_number', 'whatsapp_name', 'customer_name']); dispatch(setCurrentConversation(newCurrent)); } - } - const switchConversation = (item) => { + }; + const switchConversation = async (item) => { + if (currentConversation.sn === item.sn) { + return false; + } dispatch(setCurrentConversation(item)); if (isEmpty(item.coli_sn) || item.coli_sn === '0') { dispatch(receivedCustomerProfile({})); } + const messagesList = activeConversations[`${item.sn}`] || []; + if (isEmpty(messagesList)) { + const data = await fetchMessages({ opisn: userId, whatsappid: item.whatsapp_phone_number }); + dispatch(receivedMessageList(item.sn, data)); + } }; const onSwitchConversation = (item) => { @@ -94,16 +109,19 @@ const Conversations = (() => { navigate(`/order/chat/${item.coli_sn}`, { replace: true }); } switchConversation(item); - } + }; const handleConversationItemClose = async (item) => { console.log('invoke close', item); const data = await postConversationItemClose({ conversationid: item.sn, opisn: userId }); - } + }; return ( <> - onSwitchConversation(item)} + onSwitchConversation(item)} // onContextMenu={(item, i, e) => { // console.log(item, i, e); // return (

ppp

) @@ -112,5 +130,5 @@ const Conversations = (() => { /> ); -}); +}; export default Conversations; diff --git a/src/views/Conversations/Components/InputBox.jsx b/src/views/Conversations/Components/InputBox.jsx index f5466ec..19ee899 100644 --- a/src/views/Conversations/Components/InputBox.jsx +++ b/src/views/Conversations/Components/InputBox.jsx @@ -7,7 +7,7 @@ import { useAuthContext } from '@/stores/AuthContext'; import { LikeOutlined, MessageOutlined, StarOutlined, SendOutlined, PlusOutlined, PlusCircleOutlined } from '@ant-design/icons'; import { cloneDeep, getNestedValue, isEmpty } from '@/utils/utils'; import { v4 as uuid } from 'uuid'; -import { whatsappTemplatesParamMapped, sentMsgTypeMapped } from '@/lib/msgUtils'; +import { whatsappTemplatesParamMapped, sentMsgTypeMapped, replaceTemplateString } from '@/lib/msgUtils'; const InputBox = () => { const { loginUser } = useAuthContext(); @@ -21,6 +21,7 @@ const InputBox = () => { const invokeSendMessage = (msgObj) => { console.log('sendMessage------------------', msgObj); const contentToSend = sentMsgTypeMapped[msgObj.type].contentToSend(msgObj); + console.log('content to send-------------------------------------', contentToSend); websocket.sendMessage({ ...contentToSend, opi_sn: userId, coli_sn: currentConversation.coli_sn }); const contentToRender = sentMsgTypeMapped[msgObj.type].contentToRender(msgObj); console.log(contentToRender, 'contentToRender sendMessage------------------'); @@ -57,26 +58,38 @@ const InputBox = () => { template: { name: fromTemplate.name, language: { code: fromTemplate.language }, - ...(fromTemplate.components.body[0]?.example?.body_text?.[0]?.length > 0 - ? { - components: [ - { - 'type': 'body', - 'parameters': whatsappTemplatesParamMapped[fromTemplate.name].map((v) => ({ type: 'text', text: getNestedValue(_conversation, v) || '' })), - // [ - // { - // 'type': 'text', - // 'text': getNestedValue(_conversation, whatsappTemplatesParamMapped[fromTemplate.name][0]) , - // }, - // { // debug: - // 'type': 'text', - // 'text': getNestedValue(_conversation, whatsappTemplatesParamMapped[fromTemplate.name]?.[1] || whatsappTemplatesParamMapped[fromTemplate.name][0]) , - // }, - // ], - }, - ], - } - : {}), + components: fromTemplate.components_origin.map(citem => { + const params = whatsappTemplatesParamMapped[fromTemplate.name].map((v) => ({ type: 'text', text: getNestedValue(_conversation, v) || '' })); + const paramText = params.map((p) => p.text); + const fillTemplate = paramText.length ? replaceTemplateString(citem?.text || '', paramText) : citem?.text || ''; + + return { + type: citem.type.toLowerCase(), + parameters: params, + text: fillTemplate, + }; + }), + // ...(fromTemplate.components.body[0]?.example?.body_text?.[0]?.length > 0 + // ? { + // components: [ + // { + // 'type': 'body', + // 'text': fromTemplate.components.body[0]?.text, + // 'parameters': whatsappTemplatesParamMapped[fromTemplate.name].map((v) => ({ type: 'text', text: getNestedValue(_conversation, v) || '' })), + // // [ + // // { + // // 'type': 'text', + // // 'text': getNestedValue(_conversation, whatsappTemplatesParamMapped[fromTemplate.name][0]) , + // // }, + // // { // debug: + // // 'type': 'text', + // // 'text': getNestedValue(_conversation, whatsappTemplatesParamMapped[fromTemplate.name]?.[1] || whatsappTemplatesParamMapped[fromTemplate.name][0]) , + // // }, + // // ], + // }, + // ], + // } + // : {}), }, template_origin: fromTemplate, };