You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
385 lines
14 KiB
JavaScript
385 lines
14 KiB
JavaScript
import React, { useEffect, useState, useRef, useCallback } from 'react';
|
|
import { useParams, useNavigate, useLocation } from 'react-router-dom';
|
|
import { App, Input, Button, Empty, Tooltip, List } from 'antd';
|
|
import { PlusOutlined, LoadingOutlined, HistoryOutlined, FireOutlined,AudioTwoTone } from '@ant-design/icons';
|
|
import { fetchConversationsList, fetchOrderConversationsList, CONVERSATION_PAGE_SIZE } from '@/actions/ConversationActions';
|
|
import ConversationsNewItem from './ConversationsNewItem';
|
|
import { debounce, flush, isEmpty, isNotEmpty, pick } from '@/utils/commons';
|
|
import useConversationStore from '@/stores/ConversationStore';
|
|
import useAuthStore from '@/stores/AuthStore';
|
|
// import { useOrderStore, OrderLabelDefaultOptions, OrderStatusDefaultOptions } from "@/stores/OrderStore";
|
|
import { useVisibilityState } from '@/hooks/useVisibilityState';
|
|
import ChatListItem from './Components/ChatListItem';
|
|
import ChatListFilter from './Components/ChatListFilter';
|
|
import useStyleStore from '@/stores/StyleStore';
|
|
import dayjs from 'dayjs';
|
|
import { DATETIME_FORMAT } from '@/config';
|
|
|
|
|
|
/**
|
|
* []
|
|
*/
|
|
const Conversations = () => {
|
|
const { message } = App.useApp();
|
|
const [mobile] = useStyleStore((state) => [state.mobile]);
|
|
const routerReplace = mobile === false ? true : false; // : true;
|
|
const routePrefix = mobile === false ? `/order/chat` : `/m/chat`;
|
|
const { state: orderRow } = useLocation();
|
|
const { coli_guest_WhatsApp, guest_email } = orderRow || {};
|
|
const { order_sn } = useParams();
|
|
const navigate = useNavigate();
|
|
const userId = useAuthStore((state) => state.loginUser.userId);
|
|
|
|
const initialState = useConversationStore((state) => state.initialState);
|
|
|
|
// const [customerDetail] = useOrderStore((s) => [s.customerDetail])
|
|
|
|
const [currentConversation, setCurrentConversation, updateCurrentConversation] = useConversationStore((state) => [state.currentConversation, state.setCurrentConversation, state.updateCurrentConversation]);
|
|
const [topList, pageList, conversationsList] = useConversationStore((state) => [state.topList, state.pageList, state.conversationsList]);
|
|
const [conversationsListLoading, setConversationsListLoading] = useConversationStore((state) => [state.conversationsListLoading, state.setConversationsListLoading]);
|
|
const addToConversationList = useConversationStore((state) => state.addToConversationList);
|
|
const setConversationsList = useConversationStore((state) => state.setConversationsList);
|
|
|
|
const isVisible = useVisibilityState();
|
|
|
|
const [{ search: searchContent, loadNextPage, ...filterState }, setSearchContent, setFilter] = useConversationStore((state) => [state.filter, state.setFilterSearch, state.setFilter])
|
|
|
|
const [activeList, setActiveList] = useState(true);
|
|
const [currentLoading, setCurrentLoading] = useState(false);
|
|
const [shouldFetchCList, setShouldFetchCList] = useState(true);
|
|
|
|
/**
|
|
*
|
|
*/
|
|
let refreshing = false;
|
|
async function refreshConversationList(current='', append=false) {
|
|
// console.log('invoke -- refreshConversationList', current, conversationsListLoading, refreshing);
|
|
if (refreshing !== false) {
|
|
return false;
|
|
}
|
|
refreshing = true;
|
|
// setConversationsListLoading(mobile !== undefined ? true : false);
|
|
setConversationsListLoading(true);
|
|
setCurrentLoading(current==='');
|
|
|
|
const [otypeC, v] = filterState.otype ? filterState.otype.split('@') : [];
|
|
const otypeV = v ? parseInt(v) : '';
|
|
const searchParams = {
|
|
keyword: searchContent,
|
|
tags: filterState.tags.join(','),
|
|
olabel: otypeC === 'label' ? otypeV : '',
|
|
ostate: otypeC === 'state' ? otypeV : '',
|
|
intour: otypeC === 'intour' ? otypeV : '',
|
|
istoday: otypeC === 'istoday' ? otypeV : '',
|
|
session_enable: activeList ? 1 : 0,
|
|
lastpagetime: current ?
|
|
dayjs(current).add(1, 'minutes').format('YYYY-MM-DDTHH:mm:ss')
|
|
: append
|
|
? filterState.lastpagetime
|
|
: '',
|
|
lastactivetime: filterState.lastactivetime,
|
|
}
|
|
|
|
const _list = await fetchConversationsList({ ...searchParams, opisn: userId });
|
|
// const _list = DebounceFetchList({ ...searchParams, opisn: userId });
|
|
|
|
if (current) {
|
|
addToConversationList(_list, 'next');
|
|
} else if (append === false) {
|
|
// 搜索时, 清空列表
|
|
setConversationsList(_list)
|
|
} else {
|
|
addToConversationList(_list, 'next');
|
|
}
|
|
const pageTimeArr = flush(_list.map(item => item.lasttime));
|
|
const _lasttime = pageTimeArr.pop()
|
|
setFilter({
|
|
lastpagetime: _lasttime || '',
|
|
loadNextPage: !(_list.length === 0 || _list.length < CONVERSATION_PAGE_SIZE),
|
|
// ...((_list.length === 0 || _list.length < CONVERSATION_PAGE_SIZE) ? {
|
|
// lastactivetime: dayjs(filterState.lastactivetime).subtract(6, 'months').format(DATETIME_FORMAT),
|
|
// } : {}),
|
|
|
|
});
|
|
refreshing = false;
|
|
setConversationsListLoading(false);
|
|
setCurrentLoading(false);
|
|
}
|
|
|
|
useEffect(() => {
|
|
// console.log('effect []');
|
|
if (mobile !== false) {
|
|
setCurrentConversation({});
|
|
} else
|
|
if (order_sn ) {
|
|
setCurrentConversation({ coli_sn: Number(order_sn), sn: null })
|
|
// updateCurrentConversation({ coli_sn: Number(order_sn) });
|
|
}
|
|
return () => {};
|
|
}, []);
|
|
|
|
// useEffect(() => {
|
|
// if (order_sn && shouldFetchCList) {
|
|
// setCurrentConversation({ coli_sn: Number(order_sn) })
|
|
// // updateCurrentConversation({ coli_sn: Number(order_sn) });
|
|
// } else {
|
|
// // setCurrentConversation({ coli_sn: order_sn })
|
|
// }
|
|
|
|
// return () => {}
|
|
// }, [order_sn])
|
|
|
|
|
|
|
|
useEffect(() => {
|
|
// console.log('effect isVisible', isVisible);
|
|
if (isVisible && initialState) {
|
|
refreshConversationList(new Date()); // 无感刷新, 不显示上面的loading,
|
|
}
|
|
|
|
return () => {};
|
|
}, [isVisible]);
|
|
|
|
useEffect(() => {
|
|
// console.log('effect activeList');
|
|
if (isVisible && initialState) {
|
|
refreshConversationList(); // 显示loading
|
|
}
|
|
|
|
return () => {};
|
|
}, [activeList]);
|
|
|
|
const [dataSource, setDataSource] = useState(conversationsList);
|
|
const [listUpdateFlag, setListUpdateFlag] = useState();
|
|
|
|
const [switchToC, setSwitchToC] = useState({});
|
|
|
|
useEffect(() => {
|
|
setDataSource([...topList, ...pageList]);
|
|
// setDataSource(activeList ? conversationsList: closedConversationsList);
|
|
return () => {};
|
|
}, [conversationsList, topList, pageList, listUpdateFlag, currentConversation.unread_msg_count]);
|
|
|
|
let orderChatRefreshing = false;
|
|
useEffect(() => {
|
|
|
|
// console.log('first', isEmpty(currentConversation.sn) , order_sn , shouldFetchCList , initialState)
|
|
// isEmpty(currentConversation.sn) &&
|
|
if (order_sn && shouldFetchCList && initialState) {
|
|
getOrderConversationList(order_sn)
|
|
}
|
|
|
|
return () => {}
|
|
}, [order_sn, shouldFetchCList, initialState])
|
|
|
|
|
|
const getOrderConversationList = async (colisn) => {
|
|
if (orderChatRefreshing !== false) {
|
|
return false;
|
|
}
|
|
orderChatRefreshing = true;
|
|
|
|
const { whatsapp_phone_number } = switchToC;
|
|
const whatsappID = coli_guest_WhatsApp || whatsapp_phone_number || '';
|
|
const _email = guest_email || '';
|
|
// if (isEmpty(conversationsList)) {
|
|
// return false;
|
|
// }
|
|
|
|
let findCurrentOrderChats;
|
|
let findCurrentIndex;
|
|
let findCurrent;
|
|
|
|
// let findCurrentOrderChats = conversationsList.filter((item) => `${item.coli_sn}` === `${colisn}`);
|
|
// 使用opisn + whatsappID 判断, 解决订单修改whatsappID号码之后获取新会话, 登录账号此处省略
|
|
if (!isEmpty(whatsappID) || !isEmpty(_email)) {
|
|
|
|
findCurrentOrderChats = conversationsList.filter(
|
|
(item) => `${item.coli_sn}` === `${colisn}` && (`${item.whatsapp_phone_number}` === `${whatsappID}` || `${item.channels?.email}` === `${_email}`)
|
|
)
|
|
findCurrentIndex = isEmpty(findCurrentOrderChats) ? -1 : 0; // findCurrentOrderChats.length-1;
|
|
findCurrent = findCurrentOrderChats[findCurrentIndex];
|
|
|
|
if (findCurrentIndex !== -1) {
|
|
addToConversationList(findCurrentOrderChats, 'top');
|
|
} else // if (!isEmpty(whatsappID))
|
|
{
|
|
try {
|
|
setShouldFetchCList(false);
|
|
const data = await fetchOrderConversationsList({ opisn: userId, colisn: colisn, whatsappid: whatsappID, email: _email });
|
|
if (!isEmpty(data)) {
|
|
addToConversationList(data);
|
|
findCurrentIndex = 0; // data.length-1; // data.lastIndexOf((item) => item.coli_sn === Number(colisn));
|
|
findCurrent = data[findCurrentIndex];
|
|
} else {
|
|
// findCurrentIndex = conversationsList.findIndex((item) => item.coli_sn === Number(colisn)); // data.findIndex((item) => item.sn === currentConversation.sn);
|
|
}
|
|
} catch (error) {
|
|
// message.warning('获取订单会话失败')
|
|
}
|
|
}
|
|
}
|
|
else {
|
|
// if (isEmpty(whatsappID) && findCurrentIndex === undefined) {
|
|
// 刷新页面
|
|
findCurrentIndex = conversationsList.findIndex((item) => `${item.coli_sn}` === `${colisn}`);
|
|
findCurrent = conversationsList[findCurrentIndex];
|
|
}
|
|
orderChatRefreshing = false;
|
|
if (findCurrentIndex >= 0) {
|
|
setCurrentConversation(findCurrent);
|
|
return findCurrent;
|
|
} else {
|
|
// reset chat window
|
|
// setCurrentConversation({ sn: '', customer_name: '', coli_sn: order_sn });
|
|
return false;
|
|
}
|
|
};
|
|
|
|
const onSwitchConversation = async (item) => {
|
|
setCurrentConversation(item);
|
|
|
|
setShouldFetchCList(false);
|
|
if (isEmpty(item.coli_sn)) {
|
|
navigate(routePrefix, { replace: true });
|
|
} else {
|
|
setSwitchToC(item);
|
|
setShouldFetchCList(false);
|
|
navigate(`${routePrefix}/${item.coli_sn}`, { replace: routerReplace });
|
|
}
|
|
// if (!isEmpty(item.coli_sn)) {
|
|
// setSwitchToC(item);
|
|
// setShouldFetchCList(false);
|
|
// navigate(`/order/chat/${item.coli_sn}`, { replace: true });
|
|
// } else {
|
|
// navigate(`/order/chat`, { replace: true });
|
|
// }
|
|
// switchConversation(item);
|
|
};
|
|
|
|
const searchInputRef = useRef(null);
|
|
|
|
const [newChatModalVisible, setNewChatModalVisible] = useState(false);
|
|
const [editingChat, setEditingChat] = useState({});
|
|
|
|
// const closedVisible = closedConversationsList.length > 0;
|
|
const toggleClosedConversationsList = () => {
|
|
setActiveList(!activeList);
|
|
setCurrentConversation({});
|
|
};
|
|
|
|
const [searchInput, setSearchInput] = useState(searchContent);
|
|
|
|
|
|
return (
|
|
<div className='flex flex-col h-inherit'>
|
|
<div className='flex gap-1 items-center'>
|
|
<Button
|
|
onClick={() => {
|
|
setNewChatModalVisible(true)
|
|
setEditingChat({})
|
|
}}
|
|
icon={<PlusOutlined />}
|
|
type={'primary'}
|
|
ghost
|
|
shape={'circle'}
|
|
size='small'
|
|
/>
|
|
<Input.Search
|
|
className=''
|
|
ref={searchInputRef}
|
|
allowClear
|
|
value={searchInput}
|
|
onChange={(e) => {
|
|
setSearchInput(e.target.value)
|
|
// setTabCnt(-1)
|
|
// setTabSelectedConversation({})
|
|
}}
|
|
// onKeyDown={(e) => {
|
|
// if (e.key === 'Tab') {
|
|
// e.preventDefault()
|
|
// const _this = tabCnt >= dataSource.length - 1 ? 0 : tabCnt + 1
|
|
// setTabCnt(_this)
|
|
// setTabSelectedConversation(dataSource[_this])
|
|
// }
|
|
// }}
|
|
onPressEnter={(e) => {
|
|
// searchInputRef.current.blur()
|
|
setSearchContent(e.target.value)
|
|
// onSwitchConversation(dataSource[tabCnt < 0 ? 0 : tabCnt])
|
|
// setTabCnt(-1)
|
|
// setTabSelectedConversation({})
|
|
return false
|
|
}}
|
|
onSearch={(v, e, { source }) => setSearchContent(v)}
|
|
placeholder={`名称/号码/订单号${conversationsListLoading ? '...' : ''}`}
|
|
// addonBefore={filterTag}
|
|
// addonBefore={<FilterOutlined />}
|
|
// enterButton={'Filter'}
|
|
/>
|
|
{/* TODO 这个在完成搜索历史会话后去掉,待讨论查询规则 */}
|
|
|
|
{conversationsListLoading ? (
|
|
<div className='text-center py-1 px-2'>
|
|
<LoadingOutlined className='text-orange-400 ' />
|
|
</div>
|
|
) :
|
|
<Tooltip key={'conversation-list'} title={activeList ? '🗂已处理' : '活跃会话'}>
|
|
<Button onClick={toggleClosedConversationsList} icon={activeList ? '🗂' : '📌'} type='text' />
|
|
</Tooltip>
|
|
}
|
|
{mobile && (
|
|
<AudioTwoTone className='px-2'
|
|
onClick={() => {
|
|
navigate(`/callcenter/call`)
|
|
}}
|
|
/>
|
|
)}
|
|
</div>
|
|
<ChatListFilter key='chat-list-filter'
|
|
onFilterChange={(d) => {
|
|
refreshConversationList()
|
|
}}
|
|
activeList={activeList}
|
|
/>
|
|
<div className='flex-1 overflow-x-hidden overflow-y-auto relative'>
|
|
{/* {mobile && conversationsListLoading && dataSource.length === 0 ? ( */}
|
|
|
|
<List
|
|
itemLayout='vertical'
|
|
dataSource={dataSource}
|
|
loadMore={
|
|
<div className='text-center pt-3 mb-3 h-8 leading-8 '>
|
|
{!conversationsListLoading && loadNextPage ? (
|
|
<Button onClick={() => refreshConversationList(false, true)} size='small'>load more</Button>
|
|
) : null}
|
|
{conversationsListLoading && <LoadingOutlined className='text-primary ' />}
|
|
</div>
|
|
}
|
|
renderItem={(item, index) => (
|
|
<ChatListItem
|
|
key={item.sn}
|
|
{...{
|
|
item,
|
|
refreshConversationList,
|
|
setListUpdateFlag,
|
|
onSwitchConversation,
|
|
setNewChatModalVisible,
|
|
setEditingChat,
|
|
conversationsListLoading,
|
|
}}
|
|
/>
|
|
)}
|
|
/>
|
|
</div>
|
|
<ConversationsNewItem
|
|
initialValues={{ ...editingChat, is_current_order: false }}
|
|
open={newChatModalVisible}
|
|
onCreate={() => setNewChatModalVisible(false)}
|
|
onCancel={() => setNewChatModalVisible(false)}
|
|
/>
|
|
</div>
|
|
)
|
|
};
|
|
export default Conversations;
|