From bd078bfe5876463f8687602322d035c66434e428 Mon Sep 17 00:00:00 2001 From: Lei OT Date: Fri, 15 Mar 2024 15:15:52 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E5=8E=86=E5=8F=B2=E6=B6=88=E6=81=AF?= =?UTF-8?q?=E6=9F=A5=E8=AF=A2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit fix: 历史记录: 模板没有参数显示undefined perf: 模板填充: 匹配free style中的参数 --- src/actions/ConversationActions.js | 44 ++- src/components/SearchInput.jsx | 1 + src/lib/msgUtils.js | 4 +- src/stores/FormStore.js | 4 + src/views/ChatHistory.jsx | 339 +++++++++++------- .../Components/Input/Template.jsx | 2 +- 6 files changed, 261 insertions(+), 133 deletions(-) diff --git a/src/actions/ConversationActions.js b/src/actions/ConversationActions.js index e12a4c6..991eb94 100644 --- a/src/actions/ConversationActions.js +++ b/src/actions/ConversationActions.js @@ -1,8 +1,9 @@ -import { groupBy } from '@/utils/utils'; +import { groupBy, pick } from '@/utils/utils'; import { fetchJSON, postJSON } from '@/utils/request' import { parseRenderMessageList } from '@/lib/msgUtils'; import { API_HOST } from '@/config'; +import { isEmpty } from '@/utils/commons'; export const fetchTemplates = async () => { const data = await fetchJSON(`${API_HOST}/listtemplates`); @@ -17,7 +18,8 @@ export const fetchTemplates = async () => { * @param {object} params { opisn } */ export const fetchConversationsList = async (params) => { - const { result: data } = await fetchJSON(`${API_HOST}/getconversations`, params); + const { errcode, result: data } = await fetchJSON(`${API_HOST}/getconversations`, params); + if (errcode !== 0) return []; const list = (data || []).map((ele) => ({ ...ele, customer_name: `${ele.whatsapp_name || ''}`.trim(), whatsapp_name: `${ele.whatsapp_name || ''}`.trim() })); return list; }; @@ -72,3 +74,41 @@ export const fetchCleanUnreadMsgCount = async (params) => { * ------------------------------------------------------------------------------------------------ * 历史记录 */ +/** + * @param {object} params { search, from_date, end_date, whatsapp_id, opisn, coli_id, msg_type } + * @todo msg_type + */ +export const fetchConversationsSearch = async (params) => { + const { errcode, result: data } = await fetchJSON(`${API_HOST}/conversation_search`, params); + const list = + errcode !== 0 + ? [] + : (data || []).map((ele) => ({ + ...ele, + customer_name: `${ele.whatsapp_name || ''}`.trim(), + whatsapp_name: `${ele.whatsapp_name || ''}`.trim(), + matchMsgList: parseRenderMessageList((ele.msglist_AsJOSN || [])), // .reverse()), + })); + return list; +}; + +/** + * + * @param {object} params { opisn, whatsappid, lasttime, pagesize, pagedir } + */ +export const fetchMessagesHistory = async (params) => { + const defaultParams = { + opisn: '', + whatsappid: '', + lasttime: '2024-01-01T00:00:00', + pagesize: MESSAGE_PAGE_SIZE, + pagedir: 'next', + }; + const _params = pick(params, Object.keys(defaultParams)); + if (isEmpty(_params.opisn) || isEmpty(_params.whatsappid)) { + return []; + } + const { errcode, result } = await fetchJSON(`${API_HOST}/get_item_messages`, {...defaultParams, ..._params}); + const data = errcode !== 0 ? [] : result; // _params.pagedir === 'next' ? result.reverse() : result; + return parseRenderMessageList(data); +} diff --git a/src/components/SearchInput.jsx b/src/components/SearchInput.jsx index cf61f9d..cfd7354 100644 --- a/src/components/SearchInput.jsx +++ b/src/components/SearchInput.jsx @@ -30,6 +30,7 @@ function DebounceSelect({ fetchOptions, debounceTimeout = 800, ...props }) { showSearch allowClear {...props} + maxTagCount={1} onSearch={debounceFetcher} notFoundContent={fetching ? : null} optionFilterProp='label' diff --git a/src/lib/msgUtils.js b/src/lib/msgUtils.js index 35bcc13..38b57cf 100644 --- a/src/lib/msgUtils.js +++ b/src/lib/msgUtils.js @@ -408,8 +408,8 @@ export const whatsappMsgTypeMapped = { template: { type: 'text', data: (msg) => { - const templateDataMapped = msg.template?.components ? msg.template.components.reduce((r, v) => ({ ...r, [v.type]: v }), {}) : null; - return { id: msg.wamid, text: autoLinkText(templateDataMapped?.body?.text || `......${templateDataMapped?.body?.parameters.map(pv => pv?.text || '').join('......')}......`), title: msg.template.name }; + const templateDataMapped = msg.template?.components ? msg.template.components.reduce((r, v) => ({ ...r, [v.type]: v }), {}) : {}; + return { id: msg.wamid, text: autoLinkText(templateDataMapped?.body?.text || `......${(templateDataMapped?.body?.parameters || []).map(pv => pv?.text || '').join('......')}......`), title: msg.template.name }; }, renderForReply: (msg) => { const templateDataMapped = msg.template?.components ? msg.template.components.reduce((r, v) => ({ ...r, [v.type]: v }), {}) : null; diff --git a/src/stores/FormStore.js b/src/stores/FormStore.js index 68ef9ef..d79605b 100644 --- a/src/stores/FormStore.js +++ b/src/stores/FormStore.js @@ -8,6 +8,10 @@ export const useFormStore = create( setChatHistoryForm: (chatHistoryForm) => set({ chatHistoryForm, chatHistorySelectChat: {} }), chatHistorySelectChat: {}, setChatHistorySelectChat: (chatHistorySelectChat) => set({ chatHistorySelectChat }), + msgHistorySelectMatch: {}, + setMsgHistorySelectMatch: (msgHistorySelectMatch) => set({ msgHistorySelectMatch }), + msgListParams: {}, + setMsgListParams: (msgListParams) => set(state => ({ msgListParams: {...state.msgListParams, ...msgListParams} })), // 订单跟踪页面 orderFollowForm: { diff --git a/src/views/ChatHistory.jsx b/src/views/ChatHistory.jsx index 67f176a..1882e14 100644 --- a/src/views/ChatHistory.jsx +++ b/src/views/ChatHistory.jsx @@ -1,12 +1,14 @@ import { memo, useCallback, useEffect, useRef, useState, forwardRef } from 'react'; -import { Divider, Button, Input, Layout, DatePicker, Form, List, Spin } from 'antd'; +import { Divider, Button, Input, Layout, DatePicker, Form, List, Spin, Flex } from 'antd'; +import { LoadingOutlined } from '@ant-design/icons'; import { ChatItem, MessageBox } from 'react-chat-elements'; -import { fetchConversationsList, fetchMessages, MESSAGE_PAGE_SIZE } from '@/actions/ConversationActions'; -import { isEmpty, stringToColour } from '@/utils/utils'; +import { MESSAGE_PAGE_SIZE, fetchConversationsSearch, fetchMessagesHistory } from '@/actions/ConversationActions'; +import { cloneDeep, flush, isEmpty, pick, stringToColour } from '@/utils/utils'; import useFormStore from '@/stores/FormStore'; import { fetchSalesAgent, fetchCustomerList } from '@/actions/CommonActions'; import SearchInput from '@/components/SearchInput'; +import { isNotEmpty } from '@/utils/commons'; const { Sider, Content, Header, Footer } = Layout; const { Search } = Input; @@ -18,10 +20,16 @@ const { RangePicker } = DatePicker; const SearchForm = memo(function ({ initialValues, onSubmit }) { const [form] = Form.useForm(); function handleSubmit(values) { + const multiAgents = (values?.agent || []).map(ele => ele.value).join(','); + const multiCustomers = (values?.customer || []).map(ele => ele.value).join(','); onSubmit?.({ ...values, - opisn: values?.agent?.value || '', - customer_name: values?.customer?.label || '', + opisn: multiAgents, + whatsapp_id: multiCustomers, + ...(isNotEmpty(values.msgDateRange) ? { + from_date: values.msgDateRange[0].format('YYYY-MM-DD'), + end_date: values.msgDateRange[1].format('YYYY-MM-DD'), + } : {}), }); } return ( @@ -30,29 +38,21 @@ const SearchForm = memo(function ({ initialValues, onSubmit }) { form={form} initialValues={initialValues} onFinish={handleSubmit} - style={{ - maxWidth: 'none', - }}> - - + style={{}}> + + - + + + + - {/* - - - + + + + ) : null; + const onLoadMorePre = () => { + getMessagesPre(paramsForMsgList); + // window.dispatchEvent(new Event('resize')); + }; + const loadMorePre = + paramsForMsgList.loadPrePage && chatItemMessages.length > 0 ? ( +
+ {messageListPreLoading ? : } +
+ ) : null; + + useEffect(() => { + getConversationsList(); + return () => {}; }, [formValues]); const RenderText = memo(function renderText({ str }) { @@ -168,25 +251,6 @@ function ChatHistory() { } }; - const onLoadMore = () => { - getMessages(selectedConversation); - // window.dispatchEvent(new Event('resize')); - }; - const loadMore = !loading && selectedConversation.loadNextPage ? ( -
- -
- ) : null; - const onLoadMorePre = () => { - getMessagesPre(selectedConversation); - // window.dispatchEvent(new Event('resize')); - }; - const loadMorePre = !loading && selectedConversation.loadPrePage ? ( -
- -
- ) : null; - const messagesEndRef = useRef(null); const messageRefs = useRef([]); const scrollToMessage = (id, index) => { @@ -207,84 +271,103 @@ function ChatHistory() { - + {conversationsList.map((item) => ( setSelectedConversation(item)} /> ))} -
- ( - // - // } title={item.title} description={item.msgTime} /> - //
{item.content}
- //
- (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.type === 'text' ? '' : message.title} - text={} - 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' : '', - ].join(' ')} - style={{ - backgroundColor: message.sender === 'me' ? '#ccd4ae' : '#fff', - }} - {...(message.type === 'meetingLink' - ? { - actionButtons: [ - { - onClickButton: () => { - navigator.clipboard.writeText(message.text); - }, - Component: () =>
复制
, - }, - ], + + {(selectedConversation.matchMsgList || []).length > 1 && isNotEmpty(formValues.search) &&
+ {(selectedConversation.matchMsgList).map((item) => ( + handleMatchMsgClick(item)} + /> + ))} +
} +
+ ( + // + // } title={item.title} description={item.msgTime} /> + //
{item.content}
+ //
+ (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={} + 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' : '', + ].join(' ')} + style={{ + backgroundColor: message.sender === 'me' ? '#ccd4ae' : '#fff', + }} + {...(message.type === 'meetingLink' + ? { + actionButtons: [ + { + onClickButton: () => { + navigator.clipboard.writeText(message.text); + }, + Component: () =>
复制
, + }, + ], + } + : {})} + renderAddCmp={ +
+ {message.senderName} + {message.dateString || message.localDate} + {message.statusCN} +
} - : {})} - renderAddCmp={ -
- {message.senderName} - {message.dateString || message.localDate} - {message.statusCN} -
- } - // date={null} - // status={null} + // date={null} + // status={null} + /> + )} /> - )} - /> -
+
+
diff --git a/src/views/Conversations/Components/Input/Template.jsx b/src/views/Conversations/Components/Input/Template.jsx index 8e4afda..ad257cb 100644 --- a/src/views/Conversations/Components/Input/Template.jsx +++ b/src/views/Conversations/Components/Input/Template.jsx @@ -28,7 +28,7 @@ const InputTemplate = ({ disabled = false, invokeSendMessage }) => { const currentConversation = useConversationStore((state) => state.currentConversation); const templates = useConversationStore((state) => state.templates); // 用于替换变量: customer, agent - const valueMapped = { ...cloneDeep(currentConversation), ...objectMapper(loginUser, { usernameEN: [{ key: 'agent_name' }, { key: 'your_name' }] }) }; + const valueMapped = { ...cloneDeep(currentConversation), ...objectMapper(loginUser, { usernameEN: [{ key: 'agent_name' }, { key: 'your_name' }, { key: 'your_name1' }, { key: 'your_name2' }] }) }; useEffect(() => { setDataSource(templates); return () => {};