test: 标记未未读 todo: 新建会话

dev/timezone
Lei OT 1 year ago
parent e2f2fa44ed
commit 69cc8ccf6c

@ -82,6 +82,15 @@ export const fetchCleanUnreadMsgCount = async (params) => {
return errcode !== 0 ? {} : result;
};
/**
* 标记未未读
* @param {object} body conversationItem: { sn, ... }
*/
export const fetchConversationItemUnread = async (body) => {
const { errcode, result } = await fetchJSON(`${API_HOST}/set_state_unread`, body);
return errcode !== 0 ? {} : result;
};
/**
* ------------------------------------------------------------------------------------------------
* 历史记录
@ -105,6 +114,7 @@ export const fetchConversationsSearch = async (params) => {
OPI_Name: `${ele.OPI_Name || ele.opi_name || ''}`.trim(),
dateText: dayjs((ele.lasttime || ele.lasttime)).format('MM-DD HH:mm'),
matchMsgList: parseRenderMessageList((ele.msglist_AsJOSN || [])), // .reverse()),
coli_id: '',
}));
return list;
};

@ -158,6 +158,9 @@
height: 10px;
right: -9px;
}
.chatwindow-wrapper .rce-citem-avatar{
border-bottom: 1px solid #0000000d;
}
.chatwindow-wrapper .rce-avatar-letter{
margin-top: 0;
/* margin-left: 5px; */

@ -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={'无数据'} />}

@ -13,7 +13,7 @@ export const ConversationItemForm = ({ initialValues, onFormInstanceReady }) =>
useEffect(() => {
onFormInstanceReady(form);
setFormatPhone(phoneNumberToWAID(initialValues.phone_number));
setFormatPhone(phoneNumberToWAID(initialValues.phone_number || ''));
}, []);
useEffect(() => {
@ -42,20 +42,26 @@ export const ConversationItemForm = ({ initialValues, onFormInstanceReady }) =>
<Form.Item hidden name={'wa_id'} dependencies={['phone_number']}>
<Input />
</Form.Item>
<Form.Item
name={'coli_id'}
label={initialValues?.is_current_order ? '关联当前订单' : '关联订单'}
rules={[{ required: true, message: '关联的订单' }]}
validateStatus='warning'
help='请务必确认关联的订单是否正确'>
<Input placeholder='关联的订单' disabled={initialValues?.is_current_order || false} />
</Form.Item>
<Form.Item name={'coli_sn'} label='订单SN' hidden={initialValues?.is_current_order || false} rules={[{ required: true, message: '订单SN' }]}>
<Input placeholder='订单SN' />
</Form.Item>
{/* <Form.Item name={'name'} label='' rules={[{ required: true, message: '' }]}>
<Input placeholder='请输入联系人名称' />
</Form.Item> */}
{initialValues.is_current_order && (
<>
<Form.Item
name={'coli_id'}
label={'关联当前订单'}
rules={[{ required: true, message: '关联的订单' }]}
validateStatus='warning'
help='请务必确认关联的订单是否正确'>
<Input placeholder='关联的订单' disabled={initialValues.is_current_order} />
</Form.Item>
<Form.Item name={'coli_sn'} label='订单SN' hidden={initialValues.is_current_order} rules={[{ required: true, message: '订单SN' }]}>
<Input placeholder='订单SN' />
</Form.Item>
</>
)}
{!initialValues.is_current_order && (
<Form.Item name={'name'} label='联系人名称' rules={[{ required: true, message: '请输入联系人名称' }]}>
<Input placeholder='请输入联系人名称' />
</Form.Item>
)}
</Form>
);
};

@ -85,7 +85,7 @@ function DesktopApp() {
<Link to='/order/chat'>
在线聊天
<Badge
count={totalNotify}
count={totalNotify > 0 ? totalNotify : undefined}
style={{
backgroundColor: '#52c41a',
}}

Loading…
Cancel
Save