import { memo, useCallback, useEffect, useRef, useState, forwardRef } from 'react'; import { App, Divider, Button, Input, Layout, DatePicker, Form, List, Spin, Flex, Image } from 'antd'; import { LoadingOutlined } from '@ant-design/icons'; import { ChatItem, MessageBox } from 'react-chat-elements'; 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; const { RangePicker } = DatePicker; const BIG_PAGE_SIZE = MESSAGE_PAGE_SIZE * 100; // 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 // eslint-disable-next-line react/display-name 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: 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 (
); }); function ChatHistory() { const { message: appMessage } = App.useApp() // const [formValues, setFormValues] = useState({}); const [formValues, setFormValues] = useFormStore(((state) => [state.chatHistoryForm, state.setChatHistoryForm])); const [selectedConversation, setSelectedConversation] = useFormStore(((state) => [state.chatHistorySelectChat, state.setChatHistorySelectChat])); const [selectMatch, setSelectedMatch] = useFormStore(((state) => [state.msgHistorySelectMatch, state.setMsgHistorySelectMatch])); const [paramsForMsgList, setParamsForMsgList] = useFormStore(((state) => [state.msgListParams, state.setMsgListParams])); // { opisn, whatsappid, lasttime, pagesize, pagedir } const handleSubmit = useCallback((values) => { setFormValues({ ...values }); }, []); const [conversationsListLoading, setConversationsListLoading] = useState(false); const [messageListPreLoading, setMessageListPreLoading] = useState(false); const [messageListLoading, setMessageListLoading] = useState(false); const [conversationsList, setConversationsList] = useState([]); const [chatItemMessages, setChatItemMessages] = useState([]); const [imageAlbum, setImageAlbum] = useState([]); // const [paramsForMsgList, setParamsForMsgList] = useState({ loadNextPage: true, loadPrePage: true, }); // { opisn, whatsappid, lasttime, pagesize, pagedir } // const [selectMatch, setSelectedMatch] = useState({}); const getConversationsList = async () => { // const allEmpty = Object.values(cloneDeep(formValues)).every((val) => { // return val === null || val === '' || val === undefined; // }); // if (allEmpty) return; setConversationsListLoading(true); setChatItemMessages([]); setParamsForMsgList({}); setSelectedMatch({}); const params = flush(pick(formValues, ['opisn', 'whatsapp_id', 'search', 'from_date', 'end_date', 'coli_id'])); const data = await fetchConversationsSearch(params); setConversationsListLoading(false); setConversationsList(data); if (data.length === 1) { setSelectedConversation(data[0]); } }; const getMessagesPre = async (chatItem) => { setMessageListPreLoading(true); const data = await fetchMessagesHistory({ ...chatItem, lasttime: chatItem.pretime, pagedir: 'pre', pagesize: BIG_PAGE_SIZE }); setMessageListPreLoading(false); setChatItemMessages(prevValue => data.concat(prevValue)); const loadPrePage = !(data.length === 0 || data.length < BIG_PAGE_SIZE); setParamsForMsgList({ loadPrePage }); }; const getMessagesNext = async (chatItem) => { setMessageListLoading(true); const data = await fetchMessagesHistory({...chatItem, pagedir: 'next', pagesize: BIG_PAGE_SIZE }); setMessageListLoading(false); setChatItemMessages(prevValue => prevValue.concat(data)); const loadNextPage = !(data.length === 0 || data.length < BIG_PAGE_SIZE); setParamsForMsgList({loadNextPage}); }; // 选择指定消息之后, 定位 const scrollToSelectedMessage = (selected) => { const findIndex = chatItemMessages.findIndex(item => item.id === selected.id); if (findIndex !== -1) { scrollToMessage(selected.id, findIndex); } } const handleMatchMsgClick = async (selected) => { const findIndex = chatItemMessages.findIndex(item => item.id === selected.id); if (findIndex === -1) { setMessageListLoading(true); await getMessagesPre({...paramsForMsgList }); setMessageListLoading(false); } setSelectedMatch(selected); } // 选择指定消息之后, 定位 useEffect(() => { if (selectMatch.sn) { scrollToSelectedMessage(selectMatch); } return () => {}; }, [selectMatch.sn]); // 选中会话之后, 获取消息记录 useEffect(() => { setChatItemMessages([]); setParamsForMsgList({}); setSelectedMatch({}); if (isEmpty(selectedConversation.conversationid) || isEmpty(selectedConversation.opi_sn)) { return () => {}; } const firstActionPageParams = { opisn: selectedConversation.opi_sn, whatsappid: selectedConversation.whatsapp_phone_number }; if (isEmpty(selectedConversation.matchMsgList)) { firstActionPageParams.loadPrePage = false; firstActionPageParams.loadNextPage = true; } else { firstActionPageParams.pretime = selectedConversation.matchMsgList[0].orgmsgtime; firstActionPageParams.lasttime = selectedConversation.matchMsgList[0].orgmsgtime; firstActionPageParams.loadPrePage = true; firstActionPageParams.loadNextPage = true; } setParamsForMsgList(firstActionPageParams); async function getFirstNext() { await getMessagesNext(firstActionPageParams); } async function getFirstPre() { await getMessagesPre(firstActionPageParams); } // getFirstPre(); getFirstNext(); return () => {}; }, [selectedConversation.conversationid]); // 更新是否需要显示上一页,下一页按钮 useEffect(() => { if (chatItemMessages.length > 0) { setParamsForMsgList({pretime: chatItemMessages[0].orgmsgtime, lasttime: chatItemMessages[chatItemMessages.length - 1].orgmsgtime }); setImageAlbum(chatItemMessages.filter(ele => ele.whatsapp_msg_type === 'image').map(ele => ele.data.uri)); } return () => {}; }, [chatItemMessages]) const onLoadMore = () => { getMessagesNext(paramsForMsgList); // window.dispatchEvent(new Event('resize')); }; const loadMore = !messageListLoading && paramsForMsgList.loadNextPage ? (
) : 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, className }) { 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) ? '' : ''; 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 ( {(objArr || []).map((part, index) => { if (part.type === 'link') { return ( {part.key} ); } else { return part.key; } })} ); }); const [previewVisible, setPreviewVisible] = useState(false); const [previewSrc, setPreviewSrc] = useState(); const [previewIndex, setPreviewIndex] = useState(); const onPreviewClose = () => { setPreviewSrc(''); setPreviewVisible(false); }; const handlePreview = (msg) => { switch (msg.whatsapp_msg_type) { case 'image': setPreviewVisible(true); setPreviewSrc(msg.data.uri); setPreviewIndex(imageAlbum.findIndex((url) => url === msg.data.uri)); return false; case 'document': window.open(msg.data.link || msg.data.uri, '_blank', 'noopener,noreferrer'); return false; default: return false; } }; const handlePreviewItem = (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 [focusMsg, setFocusMsg] = useState(''); const scrollToMessage = (id, index) => { const _i = index || chatItemMessages.findIndex((msg) => msg.id === id); if (_i >= 0) { messageRefs.current[_i].scrollIntoView({ behavior: 'smooth', block: 'start' }); setFocusMsg(id); } }; // eslint-disable-next-line react/display-name const MessageBoxWithRef = forwardRef((props, ref) => (
  • )); return ( <> {conversationsList.map((item) => ( setSelectedConversation(item)} /> ))} {(selectedConversation.matchMsgList || []).length > 0 && isNotEmpty(formValues.search) && (

    {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'} replyButton={false} 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' : '', focusMsg === message.id ? 'message-box-focus' : '', message.status === 'failed' ? 'failed-msg' : '', ].join(' ')} style={{ backgroundColor: message.sender === 'me' ? '#ccd4ae' : '#fff', }} {...(message.type === 'meetingLink' ? { actionButtons: [ { onClickButton: () => { navigator.clipboard.writeText(message.text); appMessage.success('复制成功😀'); }, Component: () =>
    复制
    , }, ], } : {})} renderAddCmp={
    {message.msg_direction === 'outbound' ? selectedConversation.OPI_Name : message.senderName} {message.dateString || message.localDate} {message.statusCN}
    } // date={null} // status={null} /> )} />
    {/* */}
    ); } export default ChatHistory;