|
|
|
@ -1,15 +1,17 @@
|
|
|
|
|
import { useEffect, useState, useRef } from 'react';
|
|
|
|
|
import { useParams, useNavigate, useLocation } from 'react-router-dom';
|
|
|
|
|
import { Dropdown, Input, Button, Empty, Tooltip } from 'antd';
|
|
|
|
|
import { PlusOutlined, WhatsAppOutlined, LoadingOutlined, HistoryOutlined, FireOutlined } from '@ant-design/icons';
|
|
|
|
|
import { fetchConversationsList, fetchOrderConversationsList, fetchConversationItemClose, fetchConversationsSearch, postNewConversationItem } from '@/actions/ConversationActions';
|
|
|
|
|
import { Dropdown, Input, Button, Empty, Tooltip, Tag, Select } from 'antd';
|
|
|
|
|
import { PlusOutlined, WhatsAppOutlined, LoadingOutlined, HistoryOutlined, FireOutlined, MessageFilled, FilterOutlined, PlusSquareOutlined } from '@ant-design/icons';
|
|
|
|
|
import { fetchConversationsList, fetchOrderConversationsList, fetchConversationItemClose, fetchConversationsSearch, postNewConversationItem, fetchConversationItemUnread } from '@/actions/ConversationActions';
|
|
|
|
|
import { ChatItem } from 'react-chat-elements';
|
|
|
|
|
import ConversationsNewItem from './ConversationsNewItem';
|
|
|
|
|
import { isEmpty, olog } from '@/utils/commons';
|
|
|
|
|
import useConversationStore from '@/stores/ConversationStore';
|
|
|
|
|
import useAuthStore from '@/stores/AuthStore';
|
|
|
|
|
import { useVisibilityState } from '@/hooks/useVisibilityState';
|
|
|
|
|
import { OrderLabelDefaultOptions, OrderStatusDefaultOptions, RemindStateDefaultOptions } from '@/stores/OrderStore'
|
|
|
|
|
|
|
|
|
|
const { Option, OptGroup } = Select;
|
|
|
|
|
/**
|
|
|
|
|
* []
|
|
|
|
|
*/
|
|
|
|
@ -27,6 +29,7 @@ const Conversations = ({ mobile }) => {
|
|
|
|
|
const [conversationsListLoading, setConversationsListLoading] = useConversationStore((state) => [state.conversationsListLoading, state.setConversationsListLoading]);
|
|
|
|
|
const addToConversationList = useConversationStore((state) => state.addToConversationList);
|
|
|
|
|
const delConversationitem = useConversationStore((state) => state.delConversationitem);
|
|
|
|
|
const updateConversationItem = useConversationStore((state) => state.updateConversationItem);
|
|
|
|
|
|
|
|
|
|
const closedConversationsList = useConversationStore((state) => state.closedConversationsList);
|
|
|
|
|
const setClosedConversationList = useConversationStore((state) => state.setClosedConversationList);
|
|
|
|
@ -38,7 +41,7 @@ const Conversations = ({ mobile }) => {
|
|
|
|
|
|
|
|
|
|
async function refreshConversationList() {
|
|
|
|
|
setConversationsListLoading(mobile !== undefined ? true : false);
|
|
|
|
|
const _list = await fetchConversationsList({opisn:userId});
|
|
|
|
|
const _list = await fetchConversationsList({ opisn: userId });
|
|
|
|
|
addToConversationList(_list);
|
|
|
|
|
setConversationsListLoading(false);
|
|
|
|
|
}
|
|
|
|
@ -58,7 +61,6 @@ const Conversations = ({ mobile }) => {
|
|
|
|
|
return () => {};
|
|
|
|
|
}, [isVisible]);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
const [dataSource, setDataSource] = useState(conversationsList);
|
|
|
|
|
useEffect(() => {
|
|
|
|
|
setDataSource(conversationsList);
|
|
|
|
@ -138,21 +140,46 @@ const Conversations = ({ mobile }) => {
|
|
|
|
|
setClosedConversationList(_clist);
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
const handleConversationItemUnread = async (item) => {
|
|
|
|
|
// updateConversationItem({ sn: item.sn, unread_msg_count: 1000 });
|
|
|
|
|
// const bak_dataSource = dataSource;
|
|
|
|
|
// const targetIndex = bak_dataSource.findIndex((ele) => String(ele.sn) === String(item.sn));
|
|
|
|
|
// bak_dataSource.splice(targetIndex, 1, {
|
|
|
|
|
// ...conversationsList[targetIndex],
|
|
|
|
|
// ...{ sn: item.sn, unread_msg_count: 1000 },
|
|
|
|
|
// })
|
|
|
|
|
setDataSource((prev) =>
|
|
|
|
|
prev.map((ele) => {
|
|
|
|
|
return String(ele.sn) === String(item.sn) ? { ...ele, unread_msg_count: 1000 } : ele;
|
|
|
|
|
})
|
|
|
|
|
);
|
|
|
|
|
// setDataSource(bak_dataSource);
|
|
|
|
|
// setDataSource(conversationsList);
|
|
|
|
|
await fetchConversationItemUnread({ conversationid: item.sn });
|
|
|
|
|
refreshConversationList();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const searchInputRef = useRef(null);
|
|
|
|
|
const [searchContent, setSearchContent] = useState('');
|
|
|
|
|
const handleSearchConversations = (val) => {
|
|
|
|
|
const fromSource = activeList ? conversationsList : closedConversationsList;
|
|
|
|
|
if (val.toLowerCase().trim() !== '') {
|
|
|
|
|
const res = conversationsList.filter(
|
|
|
|
|
(item) => (item.whatsapp_name.toLowerCase()).includes(val.toLowerCase().trim())
|
|
|
|
|
|| (item.whatsapp_phone_number.toLowerCase()).includes(val.toLowerCase().trim())
|
|
|
|
|
|| (item.coli_id.toLowerCase()).includes(val.toLowerCase().trim())
|
|
|
|
|
const res = fromSource.filter(
|
|
|
|
|
(item) =>
|
|
|
|
|
item.whatsapp_name.toLowerCase().includes(val.toLowerCase().trim()) ||
|
|
|
|
|
item.whatsapp_phone_number.toLowerCase().includes(val.toLowerCase().trim()) ||
|
|
|
|
|
item.coli_id.toLowerCase().includes(val.toLowerCase().trim())
|
|
|
|
|
);
|
|
|
|
|
setDataSource(res);
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
setDataSource(conversationsList);
|
|
|
|
|
setDataSource(fromSource);
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
const handleRichSearchConvs = (params) => {
|
|
|
|
|
// alert('1')
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const [newChatModalVisible, setNewChatModalVisible] = useState(false);
|
|
|
|
|
const [newChatFormValues, setNewChatFormValues] = useState();
|
|
|
|
|
const handleNewChat = async (values) => {
|
|
|
|
@ -168,7 +195,7 @@ const Conversations = ({ mobile }) => {
|
|
|
|
|
// setCurrentConversation(newItem);
|
|
|
|
|
// }
|
|
|
|
|
// setNewChatFormValues(values);
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
const [activeList, setActiveList] = useState(true);
|
|
|
|
|
// const closedVisible = closedConversationsList.length > 0;
|
|
|
|
@ -177,16 +204,41 @@ const Conversations = ({ mobile }) => {
|
|
|
|
|
setDataSource(_active ? closedConversationsList : conversationsList);
|
|
|
|
|
setActiveList(!activeList);
|
|
|
|
|
setCurrentConversation({});
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
const filterTags = [
|
|
|
|
|
{ color: 'volcano', label: '重点', value: '重点' },
|
|
|
|
|
{ color: 'success', label: '成行', value: '成行' },
|
|
|
|
|
{ color: 'gold', label: '老客户', value: '老客户' },
|
|
|
|
|
{ color: 'blue', label: '走团中', value: '走团中' },
|
|
|
|
|
{ color: 'red-inverse', label: '投诉', value: '投诉' },
|
|
|
|
|
];
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* todo: 弹出, 多选
|
|
|
|
|
*/
|
|
|
|
|
const filterTag = (
|
|
|
|
|
<Select defaultValue="" dropdownStyle={{ width: '10rem', maxHeight: 400, overflow: 'auto' }}>
|
|
|
|
|
<Option value="">所有</Option>
|
|
|
|
|
<OptGroup key={'label'} label={'标签'}>
|
|
|
|
|
{filterTags.map((item, index) => (<Option value={item.value} key={item.value}>{item.label}</Option>))}
|
|
|
|
|
</OptGroup>
|
|
|
|
|
<OptGroup key={'remind'} label={'提醒'}>
|
|
|
|
|
{RemindStateDefaultOptions.map((item, index) => (<Option value={item.value} key={item.value}>{item.label}</Option>))}
|
|
|
|
|
</OptGroup>
|
|
|
|
|
<OptGroup key={'stat'} label={'状态'}>
|
|
|
|
|
{OrderStatusDefaultOptions.map((item, index) => (<Option value={`state.${item.value}`} key={`state.${item.value}`}>{item.label}</Option>))}
|
|
|
|
|
</OptGroup>
|
|
|
|
|
</Select>
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
return (
|
|
|
|
|
<div className='flex flex-col h-inherit'>
|
|
|
|
|
<div className='flex gap-1'>
|
|
|
|
|
{[404, 383].includes(userId) && <Button onClick={() => setNewChatModalVisible(true)} icon={<PlusOutlined />} type={'primary'} />}
|
|
|
|
|
{['404', 383].includes(userId) && <Button onClick={() => setNewChatModalVisible(true)} icon={<PlusSquareOutlined />} type={'text'} className='text-primary' />}
|
|
|
|
|
<Input.Search
|
|
|
|
|
className=''
|
|
|
|
|
ref={searchInputRef}
|
|
|
|
|
onSearch={handleSearchConversations}
|
|
|
|
|
allowClear
|
|
|
|
|
value={searchContent}
|
|
|
|
|
onChange={(e) => {
|
|
|
|
@ -211,7 +263,11 @@ const Conversations = ({ mobile }) => {
|
|
|
|
|
setTabSelectedConversation({});
|
|
|
|
|
return false;
|
|
|
|
|
}}
|
|
|
|
|
placeholder={`搜索名称/号码/订单号${conversationsListLoading ? '...' : ''}`}
|
|
|
|
|
placeholder={`名称/号码/订单号${conversationsListLoading ? '...' : ''}`}
|
|
|
|
|
onSearch={handleRichSearchConvs}
|
|
|
|
|
// addonBefore={filterTag}
|
|
|
|
|
// addonBefore={<FilterOutlined />}
|
|
|
|
|
// enterButton={'Filter'}
|
|
|
|
|
/>
|
|
|
|
|
<Tooltip key={'conversation-list'} title={activeList ? '历史会话' : '活跃会话'}>
|
|
|
|
|
<Button
|
|
|
|
@ -232,12 +288,14 @@ const Conversations = ({ mobile }) => {
|
|
|
|
|
<Dropdown
|
|
|
|
|
key={item.sn}
|
|
|
|
|
menu={{
|
|
|
|
|
items: [{ label: '关闭会话', key: 'close', danger: true }],
|
|
|
|
|
items: [{ label: '标记为未读', key: 'unread' }, { label: '关闭会话', key: 'close', danger: true }, ],
|
|
|
|
|
onClick: ({ key, domEvent }) => {
|
|
|
|
|
domEvent.stopPropagation();
|
|
|
|
|
switch (key) {
|
|
|
|
|
case 'close':
|
|
|
|
|
return handleConversationItemClose(item);
|
|
|
|
|
case 'unread':
|
|
|
|
|
return handleConversationItemUnread(item);
|
|
|
|
|
|
|
|
|
|
default:
|
|
|
|
|
return;
|
|
|
|
@ -245,24 +303,35 @@ const Conversations = ({ mobile }) => {
|
|
|
|
|
},
|
|
|
|
|
}}
|
|
|
|
|
trigger={['contextMenu']}>
|
|
|
|
|
<ChatItem
|
|
|
|
|
{...item}
|
|
|
|
|
key={item.sn}
|
|
|
|
|
id={item.sn}
|
|
|
|
|
letterItem={{ id: item.whatsapp_name || item.whatsapp_phone_number, letter: (item.whatsapp_name || item.whatsapp_phone_number).slice(0, 5) }}
|
|
|
|
|
alt={item.whatsapp_name}
|
|
|
|
|
title={item.whatsapp_name || item.whatsapp_phone_number}
|
|
|
|
|
subtitle={item.coli_id}
|
|
|
|
|
date={item.last_received_time || item.last_send_time}
|
|
|
|
|
unread={item.unread_msg_count}
|
|
|
|
|
<div
|
|
|
|
|
className={[
|
|
|
|
|
'border-0 border-t1 border-solid border-neutral-200',
|
|
|
|
|
String(item.sn) === String(currentConversation.sn) ? '__active text-primary bg-whatsapp-bg' : '',
|
|
|
|
|
String(item.sn) === String(tabSelectedConversation?.sn) ? ' bg-neutral-200' : '',
|
|
|
|
|
].join(' ')}
|
|
|
|
|
statusText={<WhatsAppOutlined key={'channel'} className='text-whatsapp' />}
|
|
|
|
|
statusColor={'#fff'}
|
|
|
|
|
onClick={() => onSwitchConversation(item)}
|
|
|
|
|
/>
|
|
|
|
|
].join(' ')}>
|
|
|
|
|
<div className='pl-4 pt-1 text-xs text-right'>
|
|
|
|
|
{/* {filterTags.map((tag) => <Tag color={tag.color} key={tag.value}>{tag.label}</Tag>)} */}
|
|
|
|
|
</div>
|
|
|
|
|
<ChatItem
|
|
|
|
|
{...item}
|
|
|
|
|
key={item.sn}
|
|
|
|
|
id={item.sn}
|
|
|
|
|
letterItem={{ id: item.whatsapp_name || item.whatsapp_phone_number, letter: (item.whatsapp_name || item.whatsapp_phone_number).slice(0, 5) }}
|
|
|
|
|
alt={item.whatsapp_name}
|
|
|
|
|
title={item.whatsapp_name || item.whatsapp_phone_number}
|
|
|
|
|
subtitle={item.coli_id}
|
|
|
|
|
date={item.last_received_time || item.last_send_time}
|
|
|
|
|
unread={item.unread_msg_count > 99 ? 0 : item.unread_msg_count}
|
|
|
|
|
// className={[
|
|
|
|
|
// String(item.sn) === String(currentConversation.sn) ? '__active text-primary bg-whatsapp-bg' : '',
|
|
|
|
|
// String(item.sn) === String(tabSelectedConversation?.sn) ? ' bg-neutral-200' : '',
|
|
|
|
|
// ].join(' ')}
|
|
|
|
|
statusText={<WhatsAppOutlined key={'channel'} className='text-whatsapp' />}
|
|
|
|
|
statusColor={'#fff'}
|
|
|
|
|
onClick={() => onSwitchConversation(item)}
|
|
|
|
|
customStatusComponents={[...(item.unread_msg_count > 99 ? [() => <div className='w-4 h-4 bg-red-500 rounded-full' key={'unread'}></div>] : [])]}
|
|
|
|
|
/>
|
|
|
|
|
</div>
|
|
|
|
|
</Dropdown>
|
|
|
|
|
))}
|
|
|
|
|
{dataSource.length === 0 && <Empty description={'无数据'} />}
|
|
|
|
|