Merge branch 'main' of github.com:hainatravel/global-sales

dev/timezone
Jimmy Liow 1 year ago
commit 831e62ae9b

@ -86,6 +86,7 @@ export const fetchCleanUnreadMsgCount = async (params) => {
* ------------------------------------------------------------------------------------------------
* 历史记录
*/
export const CONVERSATION_PAGE_SIZE = 20;
/**
* @param {object} params { search, from_date, end_date, whatsapp_id, opisn, coli_id, msg_type }
* @todo msg_type
@ -102,7 +103,7 @@ export const fetchConversationsSearch = async (params) => {
whatsapp_name: `${ele.whatsapp_name || ''}`.trim(),
opi_sn: ele.OPI_SN || ele.opi_sn || 0,
OPI_Name: `${ele.OPI_Name || ele.opi_name || ''}`.trim(),
dateText: dayjs((ele.last_received_time || ele.last_send_time)).format('MM-DD HH:mm'),
dateText: dayjs((ele.lasttime || ele.lasttime)).format('MM-DD HH:mm'),
matchMsgList: parseRenderMessageList((ele.msglist_AsJOSN || [])), // .reverse()),
}));
return list;

@ -2,7 +2,7 @@ import { create } from 'zustand';
import { RealTimeAPI } from '@/channel/realTimeAPI';
import { olog, isEmpty } from '@/utils/commons';
import { receivedMsgTypeMapped, handleNotification } from '@/channel/whatsappUtils';
import { fetchConversationsList, fetchTemplates, fetchMessages } from '@/actions/ConversationActions';
import { fetchConversationsList, fetchTemplates, fetchConversationsSearch } from '@/actions/ConversationActions';
import { devtools } from 'zustand/middleware';
import { WS_URL } from '@/config';
@ -32,6 +32,7 @@ const initialConversationState = {
// templates: [],
closedConversationsList: [], // 已关闭的对话列表
conversationsList: [], // 对话列表
currentConversation: {}, // 当前对话
@ -151,6 +152,7 @@ const conversationSlice = (set, get) => ({
conversationsListLoading: false,
conversationsList: [],
currentConversation: {},
closedConversationsList: [],
setConversationsListLoading: (conversationsListLoading) => set({ conversationsListLoading }),
@ -161,6 +163,11 @@ const conversationSlice = (set, get) => ({
const conversationsMapped = conversationsList.reduce((r, v) => ({ ...r, [`${v.sn}`]: [] }), {});
return set({ conversationsList, activeConversations: conversationsMapped });
},
setClosedConversationList: (closedConversationsList) => {
const { activeConversations, } = get();
const listMapped = closedConversationsList.reduce((r, v) => ({ ...r, [`${v.sn}`]: [] }), {});
return set({ closedConversationsList, activeConversations: { ...activeConversations, ...listMapped } });
},
addToConversationList: (newList) => {
const { activeConversations, conversationsList } = get();
const conversationsIds = Object.keys(activeConversations);
@ -351,7 +358,7 @@ export const useConversationStore = create(
// side effects
fetchInitialData: async (userIds) => {
const { addToConversationList, setTemplates, setInitial, } = get();
const { addToConversationList, setTemplates, setInitial, setClosedConversationList } = get();
const conversationsList = await fetchConversationsList({ opisn: userIds });
addToConversationList(conversationsList);
@ -359,8 +366,10 @@ export const useConversationStore = create(
const templates = await fetchTemplates();
setTemplates(templates);
setInitial(true);
const closedList = await fetchConversationsSearch({ opisn: userIds, session_enable: 0 });
setClosedConversationList(closedList);
setInitial(true);
},
reset: () => set(initialConversationState),

@ -7,7 +7,7 @@ import MessagesMatchList from './Conversations/History/MessagesMatchList';
import MessagesList from './Conversations/History/MessagesList';
import ImageAlbumPreview from './Conversations/History/ImageAlumPreview';
import { flush, pick } from '@/utils/commons';
import { fetchConversationsSearch } from '@/actions/ConversationActions';
import { fetchConversationsSearch, CONVERSATION_PAGE_SIZE } from '@/actions/ConversationActions';
const { Sider, Content } = Layout;
@ -18,8 +18,12 @@ const Index = (props) => {
const [conversationsListLoading, setConversationsListLoading] = useState(false);
const [conversationsList, setConversationsList] = useState([]);
const [pageParam, setPageParam] = useState({ lasttime: '', loadNextPage: true });
const handleSubmit = useCallback((values) => {
setFormValues({ ...values });
setPageParam({ lasttime: '', loadNextPage: true });
setConversationsList([]);
}, []);
useEffect(() => {
@ -29,10 +33,14 @@ const Index = (props) => {
const getConversationsList = async () => {
setConversationsListLoading(true);
const params = flush(pick(formValues, ['opisn', 'whatsapp_id', 'search', 'from_date', 'end_date', 'coli_id']));
const data = await fetchConversationsSearch(params);
const params = flush(pick(formValues, ['opisn', 'whatsapp_id', 'search', 'from_date', 'end_date', 'coli_id', 'lasttime']));
const data = await fetchConversationsSearch({ ...params, ...pageParam, pagesize: CONVERSATION_PAGE_SIZE });
setConversationsListLoading(false);
setConversationsList(data);
setConversationsList(conversationsList.concat(data));
setPageParam({
lasttime: data.length > 0 ? data[data.length - 1].lasttime : '',
loadNextPage: !(data.length === 0 || data.length < CONVERSATION_PAGE_SIZE),
});
if (data.length === 1) {
setSelectedConversation(data[0]);
}
@ -41,11 +49,11 @@ const Index = (props) => {
<>
<SearchForm onSubmit={handleSubmit} initialValues={formValues} />
<Divider plain orientation='left' className='mb-0'></Divider>
<Layout hasSider className='h-screen chathistory-wrapper chatwindow-wrapper' style={{ maxHeight: 'calc(100% - 279px)', height: 'calc(100% - 279px)' }}>
<Sider width={300} theme={'light'} className='h-full overflow-y-auto overflow-x-hidden' style={{ maxHeight: 'calc(100vh - 279px)', height: 'calc(100vh - 279px)' }}>
<ConversationsList {...{ conversationsListLoading, conversationsList, selectedConversation, handleChatItemClick: setSelectedConversation }} />
<Layout hasSider className='h-screen chathistory-wrapper chatwindow-wrapper' style={{ maxHeight: 'calc(100% - 300px)', height: 'calc(100% - 300px)' }}>
<Sider width={300} theme={'light'} className='h-full overflow-y-auto overflow-x-hidden' style={{ maxHeight: 'calc(100vh - 300px)', height: 'calc(100vh - 300px)' }}>
<ConversationsList {...{ conversationsListLoading, conversationsList, selectedConversation, handleChatItemClick: setSelectedConversation, onLoadMore: getConversationsList, loadMoreVisible: pageParam.loadNextPage }} />
</Sider>
<Content style={{ maxHeight: 'calc(100vh - 279px)', height: 'calc(100vh - 279px)', minWidth: '360px' }}>
<Content style={{ maxHeight: 'calc(100vh - 300px)', height: 'calc(100vh - 300px)', minWidth: '360px' }}>
<Flex className='h-full relative'>
<MessagesMatchList />
<MessagesList />

@ -1,12 +1,22 @@
import { Spin } from 'antd';
import { List, Button } from 'antd';
import { ChatItem } from 'react-chat-elements';
const ConversationsList = ({ conversationsListLoading, handleChatItemClick, selectedConversation, conversationsList, ...props }) => {
const ConversationsList = ({ conversationsListLoading, handleChatItemClick, selectedConversation, conversationsList, onLoadMore, loadMoreVisible, ...props }) => {
return (
<>
<Spin spinning={conversationsListLoading}>
{conversationsList.map((item) => (
<List
loading={conversationsListLoading}
loadMore={
!conversationsListLoading && loadMoreVisible ? (
<div className='text-center pt-3 mb-3 h-8 leading-8 '>
<Button onClick={onLoadMore}>load more</Button>
</div>
) : null
}
className='relative'
itemLayout='vertical'
dataSource={conversationsList}
renderItem={(item, index) => (
<ChatItem
{...item}
key={item.conversationid}
@ -15,14 +25,13 @@ const ConversationsList = ({ conversationsListLoading, handleChatItemClick, sele
alt={`${item.whatsapp_name}`}
title={item.whatsapp_name || item.whatsapp_phone_number}
subtitle={`${item.OPI_Name || ''} ${item.coli_id || ''}`}
date={item.last_received_time || item.last_send_time}
// dateString={item.last_received_time}
date={item.lasttime || item.lasttime}
dateString={item.dateText}
className={String(item.conversationid) === String(selectedConversation.conversationid) ? '__active text-primary bg-neutral-100' : ''}
onClick={() => handleChatItemClick(item)}
/>
))}
</Spin>
)}
/>
</>
);
};

@ -1,8 +1,8 @@
import { useEffect, useState, useRef } from 'react';
import { useParams, useNavigate, useLocation } from 'react-router-dom';
import { Dropdown, Input, Button, } from 'antd';
import { PlusOutlined, WhatsAppOutlined, LoadingOutlined } from '@ant-design/icons';
import { fetchConversationsList, fetchOrderConversationsList, fetchConversationItemClose, postNewConversationItem } from '@/actions/ConversationActions';
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 { ChatItem } from 'react-chat-elements';
import ConversationsNewItem from './ConversationsNewItem';
import { isEmpty, olog } from '@/utils/commons';
@ -28,6 +28,9 @@ const Conversations = ({ mobile }) => {
const addToConversationList = useConversationStore((state) => state.addToConversationList);
const delConversationitem = useConversationStore((state) => state.delConversationitem);
const closedConversationsList = useConversationStore((state) => state.closedConversationsList);
const setClosedConversationList = useConversationStore((state) => state.setClosedConversationList);
const isVisible = useVisibilityState();
const [tabSelectedConversation, setTabSelectedConversation] = useState({});
@ -60,7 +63,7 @@ const Conversations = ({ mobile }) => {
useEffect(() => {
setDataSource(conversationsList);
return () => {};
}, [conversationsList]);
}, [conversationsList.length]);
const [switchToC, setSwitchToC] = useState({});
const [shouldFetchCList, setShouldFetchCList] = useState(true);
@ -131,6 +134,8 @@ const Conversations = ({ mobile }) => {
if (String(order_sn) === String(item.coli_sn)) {
navigate(routePrefix, { replace: routerReplace });
}
const _clist = await fetchConversationsSearch({ opisn: userId, session_enable: 0 });
setClosedConversationList(_clist);
};
const searchInputRef = useRef(null);
@ -165,10 +170,19 @@ const Conversations = ({ mobile }) => {
// setNewChatFormValues(values);
}
const [activeList, setActiveList] = useState(true);
// const closedVisible = closedConversationsList.length > 0;
const toggleClosedConversationsList = () => {
const _active = activeList;
setDataSource(_active ? closedConversationsList : conversationsList);
setActiveList(!activeList);
setCurrentConversation({});
}
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={<PlusOutlined />} type={'primary'} />}
<Input.Search
className=''
ref={searchInputRef}
@ -199,6 +213,13 @@ const Conversations = ({ mobile }) => {
}}
placeholder={`搜索名称/号码/订单号${conversationsListLoading ? '...' : ''}`}
/>
<Tooltip key={'conversation-list'} title={activeList ? '历史会话' : '活跃会话'}>
<Button
onClick={toggleClosedConversationsList}
icon={activeList ? <HistoryOutlined className='text-neutral-500' /> : <FireOutlined className=' text-orange-500' />}
type='text'
/>
</Tooltip>
</div>
<div className='flex-1 overflow-x-hidden overflow-y-auto relative'>
{conversationsListLoading && dataSource.length === 0 ? (
@ -244,8 +265,14 @@ const Conversations = ({ mobile }) => {
/>
</Dropdown>
))}
{dataSource.length === 0 && <Empty description={'无数据'} />}
</div>
<ConversationsNewItem initialValues={{coli_id: currentConversation.coli_id, coli_sn: currentConversation.coli_sn}} open={newChatModalVisible} onCreate={handleNewChat} onCancel={() => setNewChatModalVisible(false)} />
<ConversationsNewItem
initialValues={{ coli_id: currentConversation.coli_id, coli_sn: currentConversation.coli_sn }}
open={newChatModalVisible}
onCreate={handleNewChat}
onCancel={() => setNewChatModalVisible(false)}
/>
</div>
);
};

@ -139,11 +139,12 @@ export default defineConfig({
},
output: {
entryFileNames: '[name]/build.[hash].js',
// manualChunks(id) {
// if (id.includes('node_modules')) {
// return id.toString().split('node_modules/')[1].split('/')[0].toString();
// }
// },
manualChunks(id) {
if (id.includes('node_modules')) {
return 'vendor';
// return id.toString().split('node_modules/')[1].split('/')[0].toString();
}
},
// chunkFileNames: (chunkInfo) => {
// const facadeModuleId = chunkInfo.facadeModuleId ? chunkInfo.facadeModuleId.split('/') : [];
// return `assets/[name].[hash].js`;

Loading…
Cancel
Save