feat: 会话列表搜索和分页

2.0/email-builder
Lei OT 11 months ago
parent 0a28fa4457
commit 921cb2e7b9

@ -32,10 +32,11 @@ export const fetchConversationsList = async (params) => {
keyword: '', keyword: '',
ostate: '', ostate: '',
intour: '', intour: '',
lastactivetime: dayjs('2024-09-01').format('YYYY-MM-DD 00:00'), session_enable: 1,
lastactivetime: '',
} }
const combinedFilterStr = Object.values(pick(params, ['tags', 'olabel', 'intour', 'keyword', 'ostate'])).join() const combinedFilterStr = Object.values(pick(params, ['keyword', 'tags', 'olabel', 'intour', 'ostate'])).join('')
if (isNotEmpty(combinedFilterStr)) { if (isNotEmpty(combinedFilterStr) || params.session_enable === 0) {
params.lastactivetime = ''; params.lastactivetime = '';
} }
const { errcode, result: data } = await fetchJSON(`${API_HOST}/getconversations`, { ...defaultParams, ...params }) const { errcode, result: data } = await fetchJSON(`${API_HOST}/getconversations`, { ...defaultParams, ...params })
@ -46,9 +47,7 @@ export const fetchConversationsList = async (params) => {
whatsapp_name: `${ele.whatsapp_name || ''}`.trim(), whatsapp_name: `${ele.whatsapp_name || ''}`.trim(),
coli_id: ele.COLI_ID, coli_id: ele.COLI_ID,
})) }))
// return first 10 items return list;
return list.slice(0, 30); // test: 0
// return list;
}; };
/** /**

@ -0,0 +1,5 @@
const RegionCodeEmoji = ({ regionCode }) => {
const countryCode = String.fromCodePoint(...[...regionCode.toUpperCase()].map((x) => 0x1f1a5 + x.charCodeAt()))
return <span title={regionCode}>{countryCode}</span>
}
export default RegionCodeEmoji

@ -7,6 +7,11 @@ import { devtools } from 'zustand/middleware';
import { WS_URL, DATETIME_FORMAT } from '@/config'; import { WS_URL, DATETIME_FORMAT } from '@/config';
import dayjs from 'dayjs'; import dayjs from 'dayjs';
const replaceObjectsByKey = (arr1, arr2, key) => {
const map = new Map(arr2.map(ele => [ele[key], ele]));
return arr1.map(item => map.has(item[key]) ? map.get(item[key]) : item);
}
// const WS_URL = 'ws://202.103.68.144:8888/whatever/'; // const WS_URL = 'ws://202.103.68.144:8888/whatever/';
// const WS_URL = 'ws://120.79.9.217:10022/whatever/'; // const WS_URL = 'ws://120.79.9.217:10022/whatever/';
const conversationRow = { const conversationRow = {
@ -62,17 +67,17 @@ const filterObj = {
search: '', search: '',
otype: '', otype: '',
tags: [], tags: [],
status: [], loadNextPage: true,
labels: [], lastpagetime: '',
lastactivetime: '', // dayjs().subtract(30, "days").format('YYYY-MM-DD 00:00'), // 30 days
}; };
const filterSlice = (set) => ({ const filterSlice = (set) => ({
filter: structuredClone(filterObj), filter: structuredClone(filterObj),
setFilter: (filter) => set({ filter }), setFilter: (filter) => set(state => ({ filter: { ...state.filter, ...filter } })),
setFilterSearch: (search) => set((state) => ({ filter: { ...state.filter, search } })), setFilterSearch: (search) => set((state) => ({ filter: { ...state.filter, search } })),
setFilterOtype: (otype) => set((state) => ({ filter: {...state.filter, otype } })), setFilterOtype: (otype) => set((state) => ({ filter: {...state.filter, otype } })),
setFilterTags: (tags) => set((state) => ({ filter: {...state.filter, tags } })), setFilterTags: (tags) => set((state) => ({ filter: {...state.filter, tags } })),
setFilterStatus: (status) => set((state) => ({ filter: {...state.filter, status } })), setFilterLoadNextPage: (loadNextPage) => set((state) => ({ filter: {...state.filter, loadNextPage } })),
setFilterLabels: (labels) => set((state) => ({ filter: {...state.filter, labels } })),
resetFilter: () => set({ filter: structuredClone(filterObj) }), resetFilter: () => set({ filter: structuredClone(filterObj) }),
}) })
// WABA 模板 // WABA 模板
@ -187,28 +192,32 @@ const conversationSlice = (set, get) => ({
setConversationsListLoading: (conversationsListLoading) => set({ conversationsListLoading }), setConversationsListLoading: (conversationsListLoading) => set({ conversationsListLoading }),
/** /**
* @deprecated * 首次加载
* 搜索结果
*/ */
setConversationsList: (conversationsList) => { setConversationsList: (conversationsList) => {
const { activeConversations, } = get();
const conversationsMapped = conversationsList.reduce((r, v) => ({ ...r, [`${v.sn}`]: [] }), {}); const conversationsMapped = conversationsList.reduce((r, v) => ({ ...r, [`${v.sn}`]: [] }), {});
return set({ conversationsList, activeConversations: conversationsMapped }); return set({ conversationsList, activeConversations: {...conversationsMapped, ...activeConversations,} });
}, },
setClosedConversationList: (closedConversationsList) => { setClosedConversationList: (closedConversationsList) => {
const { activeConversations, } = get(); const { activeConversations, } = get();
const listMapped = closedConversationsList.reduce((r, v) => ({ ...r, [`${v.sn}`]: [] }), {}); const listMapped = closedConversationsList.reduce((r, v) => ({ ...r, [`${v.sn}`]: [] }), {});
return set({ closedConversationsList, activeConversations: { ...activeConversations, ...listMapped } }); return set({ closedConversationsList, activeConversations: { ...activeConversations, ...listMapped } });
}, },
addToConversationList: (newList) => { addToConversationList: (newList, position='top') => {
const { activeConversations, conversationsList } = get(); const { activeConversations, conversationsList } = get();
const conversationsIds = Object.keys(activeConversations); // const conversationsIds = Object.keys(activeConversations);
// const conversationsIds = conversationsList.map((chatItem) => `${chatItem.sn}`); const conversationsIds = conversationsList.map((chatItem) => `${chatItem.sn}`);
const newConversations = newList.filter((conversation) => !conversationsIds.includes(`${conversation.sn}`)); const newConversations = newList.filter((conversation) => !conversationsIds.includes(`${conversation.sn}`));
const newConversationsMapped = newConversations.reduce((r, v) => ({ ...r, [`${v.sn}`]: [] }), {}); const newConversationsMapped = newConversations.reduce((r, v) => ({ ...r, [`${v.sn}`]: [] }), {});
const newListIds = newList.map((chatItem) => `${chatItem.sn}`); const newListIds = newList.map((chatItem) => `${chatItem.sn}`);
const withoutNew = conversationsList.filter((item) => !newListIds.includes(`${item.sn}`)); const withoutNew = conversationsList.filter((item) => !newListIds.includes(`${item.sn}`));
const mergedList = [...newList, ...withoutNew]; const updateList = replaceObjectsByKey(conversationsList, newList, 'sn');
const mergedList = position==='top' ? [...newList, ...withoutNew] : [...updateList, ...newConversations];
const refreshTotalNotify = mergedList.reduce((r, c) => r+(c.unread_msg_count === UNREAD_MARK ? 0 : c.unread_msg_count), 0); const refreshTotalNotify = mergedList.reduce((r, c) => r+(c.unread_msg_count === UNREAD_MARK ? 0 : c.unread_msg_count), 0);
return set((state) => ({ return set((state) => ({
@ -408,8 +417,8 @@ export const useConversationStore = create(
const templates = await fetchTemplates(); const templates = await fetchTemplates();
setTemplates(templates); setTemplates(templates);
const closedList = await fetchConversationsSearch({ opisn: userIds, session_enable: 0 }); // const closedList = await fetchConversationsList({ opisn: userIds, session_enable: 0 });
setClosedConversationList(closedList); // setClosedConversationList(closedList);
const myTags = await fetchTags({ opisn: userIds}); const myTags = await fetchTags({ opisn: userIds});
setTags(myTags); setTags(myTags);

@ -1,7 +1,7 @@
import React, { useState, useEffect } from 'react'; import React, { useState, useEffect } from 'react';
import { Button, Tag, Radio, Popover, Form, Divider } from 'antd'; import { Button, Tag, Radio, Popover, Form, Divider } from 'antd';
import { FilterOutlined, FilterTwoTone } from '@ant-design/icons'; import { FilterOutlined, FilterTwoTone } from '@ant-design/icons';
import { isEmpty, isNotEmpty, objectMapper, stringToColour } from '@/utils/commons'; import { debounce, isEmpty, isNotEmpty, objectMapper, stringToColour } from '@/utils/commons';
import useConversationStore from '@/stores/ConversationStore'; import useConversationStore from '@/stores/ConversationStore';
import { OrderLabelDefaultOptions, OrderStatusDefaultOptions } from '@/stores/OrderStore'; import { OrderLabelDefaultOptions, OrderStatusDefaultOptions } from '@/stores/OrderStore';
import { FilterIcon } from '@/components/Icons'; import { FilterIcon } from '@/components/Icons';
@ -32,6 +32,9 @@ const ChatListFilter = ({ onFilterChange, activeList, ...props }) => {
const conversationsList = useConversationStore((state) => state.conversationsList); const conversationsList = useConversationStore((state) => state.conversationsList);
const closedConversationsList = useConversationStore((state) => state.closedConversationsList); const closedConversationsList = useConversationStore((state) => state.closedConversationsList);
/**
* 前端搜索, 返回结果到列表
*/
const handleFilter = async () => { const handleFilter = async () => {
const fromSource = activeList ? conversationsList : closedConversationsList; const fromSource = activeList ? conversationsList : closedConversationsList;
@ -72,9 +75,9 @@ const ChatListFilter = ({ onFilterChange, activeList, ...props }) => {
return isEmpty(selectedTags) ? true : (selectedTags || []).some(tele => (itemTagKeys).includes(tele)); return isEmpty(selectedTags) ? true : (selectedTags || []).some(tele => (itemTagKeys).includes(tele));
} }
const filterWithParamRes = fromSource.filter(filterSearchFun).filter(filterOTypeFun).filter(filterTagFun); // const filterWithParamRes = fromSource.filter(filterSearchFun).filter(filterOTypeFun).filter(filterTagFun);
if (typeof onFilterChange === 'function') { if (typeof onFilterChange === 'function') {
onFilterChange(filterWithParamRes); onFilterChange();
} }
}; };
@ -85,6 +88,10 @@ const ChatListFilter = ({ onFilterChange, activeList, ...props }) => {
setFilterTags(nextSelectedTags); setFilterTags(nextSelectedTags);
form.setFieldValue('tags', nextSelectedTags); form.setFieldValue('tags', nextSelectedTags);
}; };
/**
* @ignore
*/
const onFinish = async (values) => { const onFinish = async (values) => {
// const filterParam = objectMapper(values, { tags: {key:'tags', transform: (v) => v ? v.join(',') : ''} }); // const filterParam = objectMapper(values, { tags: {key:'tags', transform: (v) => v ? v.join(',') : ''} });
const filterParam = objectMapper(values, { tags: {key:'tags', } }); const filterParam = objectMapper(values, { tags: {key:'tags', } });
@ -98,16 +105,18 @@ const ChatListFilter = ({ onFilterChange, activeList, ...props }) => {
resetFilter(); resetFilter();
form.resetFields(); form.resetFields();
if (typeof onFilterChange === 'function') { if (typeof onFilterChange === 'function') {
const fromSource = activeList ? conversationsList : closedConversationsList; onFilterChange();
onFilterChange(fromSource);
} }
} }
useEffect(() => { useEffect(() => {
handleFilter() // handleFilter()
if (typeof onFilterChange === 'function') {
onFilterChange()
}
return () => {} return () => {}
}, [selectedTags, selectedOType, filter ]) }, [selectedTags, selectedOType, search ])
const [openPopup, setOpenPopup] = useState(false); const [openPopup, setOpenPopup] = useState(false);
return ( return (
@ -121,7 +130,6 @@ const ChatListFilter = ({ onFilterChange, activeList, ...props }) => {
value={selectedOType} value={selectedOType}
onChange={(e) => { onChange={(e) => {
setFilterOtype(e.target.value) setFilterOtype(e.target.value)
// handleFilter({ otype: e.target.value })
}} }}
/> />
<Popover <Popover

@ -9,6 +9,7 @@ import { flush, isEmpty, isNotEmpty, stringToColour } from '@/utils/commons';
import useConversationStore from '@/stores/ConversationStore'; import useConversationStore from '@/stores/ConversationStore';
import useAuthStore from '@/stores/AuthStore'; import useAuthStore from '@/stores/AuthStore';
import ChannelLogo from './ChannelLogo'; import ChannelLogo from './ChannelLogo';
import RegionCodeEmoji from '@/components/RegionCodeEmoji'
import { ReadIcon } from '@/components/Icons'; import { ReadIcon } from '@/components/Icons';
import useStyleStore from '@/stores/StyleStore'; import useStyleStore from '@/stores/StyleStore';
import { OrderLabelDefaultOptionsMapped, OrderStatusDefaultOptionsMapped } from '@/stores/OrderStore'; import { OrderLabelDefaultOptionsMapped, OrderStatusDefaultOptionsMapped } from '@/stores/OrderStore';
@ -28,15 +29,10 @@ const OrderSignEmoji = ({ item }) => (
<> <>
{OrderLabelDefaultOptionsMapped[String(item.order_label_id)]?.emoji} {OrderLabelDefaultOptionsMapped[String(item.order_label_id)]?.emoji}
{OrderStatusDefaultOptionsMapped[String(item.order_state_id)]?.emoji} {OrderStatusDefaultOptionsMapped[String(item.order_state_id)]?.emoji}
{item.intour === 1 ? '👣' : ''} {item.intour === 1 && item.order_state_id===5 ? '👣' : ''}
</> </>
) )
const RegionCodeEmoji = ({ regionCode }) => {
const countryCode = String.fromCodePoint(...[...regionCode.toUpperCase()].map((x) => 0x1f1a5 + x.charCodeAt()))
return <span title={regionCode}>{countryCode}</span>
}
const NewTagForm = ({onSubmit,...props}) => { const NewTagForm = ({onSubmit,...props}) => {
const [form] = Form.useForm(); const [form] = Form.useForm();
const [subLoding, setSubLoding] = useState(false); const [subLoding, setSubLoding] = useState(false);
@ -130,13 +126,13 @@ const ChatListItem = (({item, refreshConversationList,setListUpdateFlag,onSwitch
const handleConversationItemUnread = async (item) => { const handleConversationItemUnread = async (item) => {
await fetchConversationItemUnread({ conversationid: item.sn }); await fetchConversationItemUnread({ conversationid: item.sn });
await refreshConversationList(); await refreshConversationList(item.last_received_time > item.last_send_time ? item.last_received_time : item.last_send_time);
setListUpdateFlag(Math.random()); setListUpdateFlag(Math.random());
} }
const handleConversationItemTop = async (item) => { const handleConversationItemTop = async (item) => {
await fetchConversationItemTop({ conversationid: item.sn, top_state: item.top_state === 0 ? 1 : 0 }); await fetchConversationItemTop({ conversationid: item.sn, top_state: item.top_state === 0 ? 1 : 0 });
await refreshConversationList(); await refreshConversationList(item.last_received_time > item.last_send_time ? item.last_received_time : item.last_send_time);
setListUpdateFlag(Math.random()); setListUpdateFlag(Math.random());
} }
@ -155,7 +151,7 @@ const ChatListItem = (({item, refreshConversationList,setListUpdateFlag,onSwitch
addTag({ label: rtag.tag_label, key: rtag.tag_key, value: rtag.tag_key }) addTag({ label: rtag.tag_label, key: rtag.tag_key, value: rtag.tag_key })
} }
} }
await refreshConversationList(); await refreshConversationList(item.last_received_time > item.last_send_time ? item.last_received_time : item.last_send_time);
setListUpdateFlag(Math.random()); setListUpdateFlag(Math.random());
} }
@ -277,9 +273,16 @@ const ChatListItem = (({item, refreshConversationList,setListUpdateFlag,onSwitch
}}> }}>
<div <div
className={[ className={[
'border-0 border-t1 border-solid border-neutral-200', 'border-0 border-solid border-neutral-200',
String(item.sn) === String(currentConversation.sn) ? '__active text-primary bg-whatsapp-bg' : '', // item.top_state === 1 ? 'bg-stone-100' : '',
String(item.sn) === String(tabSelectedConversation?.sn) ? ' bg-neutral-200' : '', String(item.sn) === String(currentConversation.sn)
? '__active text-primary bg-whatsapp-bg'
: String(item.sn) === String(tabSelectedConversation?.sn)
? ' bg-neutral-200'
: item.top_state === 1
? 'bg-stone-100'
: '',
// String(item.sn) === String(tabSelectedConversation?.sn) ? ' bg-neutral-200' : '',
].join(' ')}> ].join(' ')}>
{/* <div className='pl-4 pt-1 text-xs text-right'> {/* <div className='pl-4 pt-1 text-xs text-right'>
{tags.map((tag) => <Tag color={tag.color} key={tag.value}>{tag.label}</Tag>)} {tags.map((tag) => <Tag color={tag.color} key={tag.value}>{tag.label}</Tag>)}
@ -291,12 +294,12 @@ const ChatListItem = (({item, refreshConversationList,setListUpdateFlag,onSwitch
letterItem={{ id: item.whatsapp_name || item.whatsapp_phone_number, letter: (item.whatsapp_name || item.whatsapp_phone_number).slice(0, 5) }} letterItem={{ id: item.whatsapp_name || item.whatsapp_phone_number, letter: (item.whatsapp_name || item.whatsapp_phone_number).slice(0, 5) }}
alt={item.whatsapp_name} alt={item.whatsapp_name}
title={ title={
<> <span>
{/* 🔝 */}
{/* <RegionCodeEmoji regionCode={item?.last_message?.regionCode || ''} /> */} {/* <RegionCodeEmoji regionCode={item?.last_message?.regionCode || ''} /> */}
{(item.top_state === 1 ? '🔝' : '') {item.conversation_memo || item.whatsapp_name || item.whatsapp_phone_number}
+ (item.conversation_memo || item.whatsapp_name || item.whatsapp_phone_number)} </span>
</> // item.conversation_memo ||
// item.conversation_memo ||
} }
// subtitle={item.coli_id} // subtitle={item.coli_id}
subtitle={ subtitle={
@ -306,7 +309,7 @@ const ChatListItem = (({item, refreshConversationList,setListUpdateFlag,onSwitch
{/* <SentIcon /> */} {/* <SentIcon /> */}
{/* <span>{item.coli_id}</span> */} {/* <span>{item.coli_id}</span> */}
{/* <span><ReadIcon />最后一条消息</span> */} {/* <span><ReadIcon />最后一条消息</span> */}
<span> <span className='text-sm'>
<RenderLastMsg {...item?.last_message} /> <RenderLastMsg {...item?.last_message} />
</span> </span>
<div className='text-sm'> <div className='text-sm'>
@ -320,7 +323,7 @@ const ChatListItem = (({item, refreshConversationList,setListUpdateFlag,onSwitch
</div> </div>
</div> </div>
} }
date={item.last_received_time || item.last_send_time} date={item.lasttime || item.last_received_time || item.last_send_time}
unread={item.unread_msg_count > 99 ? 0 : item.unread_msg_count} unread={item.unread_msg_count > 99 ? 0 : item.unread_msg_count}
// className={[ // className={[
// String(item.sn) === String(currentConversation.sn) ? '__active text-primary bg-whatsapp-bg' : '', // String(item.sn) === String(currentConversation.sn) ? '__active text-primary bg-whatsapp-bg' : '',

@ -1,16 +1,18 @@
import React, { useEffect, useState, useRef } from 'react'; import React, { useEffect, useState, useRef, useCallback } from 'react';
import { useParams, useNavigate, useLocation } from 'react-router-dom'; import { useParams, useNavigate, useLocation } from 'react-router-dom';
import { Input, Button, Empty, Tooltip } from 'antd'; import { Input, Button, Empty, Tooltip, List } from 'antd';
import { PlusOutlined, LoadingOutlined, HistoryOutlined, FireOutlined,AudioTwoTone } from '@ant-design/icons'; import { PlusOutlined, LoadingOutlined, HistoryOutlined, FireOutlined,AudioTwoTone } from '@ant-design/icons';
import { fetchConversationsList, fetchOrderConversationsList } from '@/actions/ConversationActions'; import { fetchConversationsList, fetchOrderConversationsList, CONVERSATION_PAGE_SIZE } from '@/actions/ConversationActions';
import ConversationsNewItem from './ConversationsNewItem'; import ConversationsNewItem from './ConversationsNewItem';
import { isEmpty } from '@/utils/commons'; import { debounce, isEmpty, isNotEmpty, pick } from '@/utils/commons';
import useConversationStore from '@/stores/ConversationStore'; import useConversationStore from '@/stores/ConversationStore';
import useAuthStore from '@/stores/AuthStore'; import useAuthStore from '@/stores/AuthStore';
import { useVisibilityState } from '@/hooks/useVisibilityState'; import { useVisibilityState } from '@/hooks/useVisibilityState';
import ChatListItem from './Components/ChatListItem'; import ChatListItem from './Components/ChatListItem';
import ChatListFilter from './Components/ChatListFilter'; import ChatListFilter from './Components/ChatListFilter';
import useStyleStore from '@/stores/StyleStore'; import useStyleStore from '@/stores/StyleStore';
import dayjs from 'dayjs';
import { DATETIME_FORMAT } from '@/config';
/** /**
* [] * []
@ -29,19 +31,61 @@ const Conversations = () => {
const conversationsList = useConversationStore((state) => state.conversationsList); const conversationsList = useConversationStore((state) => state.conversationsList);
const [conversationsListLoading, setConversationsListLoading] = useConversationStore((state) => [state.conversationsListLoading, state.setConversationsListLoading]); const [conversationsListLoading, setConversationsListLoading] = useConversationStore((state) => [state.conversationsListLoading, state.setConversationsListLoading]);
const addToConversationList = useConversationStore((state) => state.addToConversationList); const addToConversationList = useConversationStore((state) => state.addToConversationList);
const setConversationsList = useConversationStore((state) => state.setConversationsList);
const closedConversationsList = useConversationStore((state) => state.closedConversationsList);
const isVisible = useVisibilityState(); const isVisible = useVisibilityState();
const [tabSelectedConversation, setTabSelectedConversation] = useState({}); const [tabSelectedConversation, setTabSelectedConversation] = useState({});
const [tabCnt, setTabCnt] = useState(-1); const [tabCnt, setTabCnt] = useState(-1);
async function refreshConversationList() { const [{ search: searchContent, loadNextPage, ...filterState }, setSearchContent, setFilter] = useConversationStore((state) => [state.filter, state.setFilterSearch, state.setFilter])
setConversationsListLoading(mobile !== undefined ? true : false);
const _list = await fetchConversationsList({ opisn: userId }); const [currentLoading, setCurrentLoading] = useState(false);
addToConversationList(_list); /**
*
*/
async function refreshConversationList(current='', append=false) {
// 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 : '',
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 });
// ,
if (current) {
addToConversationList(_list, 'next');
} else if (append === false) {
setConversationsList(_list)
} else {
addToConversationList(_list, 'next');
}
setFilter({
lastpagetime: _list.length > 0 ? _list[_list.length - 1].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),
// } : {}),
});
setConversationsListLoading(false); setConversationsListLoading(false);
setCurrentLoading(false);
} }
useEffect(() => { useEffect(() => {
@ -51,21 +95,29 @@ const Conversations = () => {
return () => {}; return () => {};
}, []); }, []);
const [activeList, setActiveList] = useState(true);
useEffect(() => { useEffect(() => {
if (isVisible) { if (isVisible && initialState) {
refreshConversationList(); refreshConversationList(new Date()); // , loading,
} }
return () => {}; return () => {};
}, [isVisible]); }, [isVisible]);
const [activeList, setActiveList] = useState(true); useEffect(() => {
if (isVisible && initialState) {
refreshConversationList(); // loading
}
return () => {};
}, [activeList]);
const [dataSource, setDataSource] = useState(conversationsList); const [dataSource, setDataSource] = useState(conversationsList);
const [listUpdateFlag, setListUpdateFlag] = useState(); const [listUpdateFlag, setListUpdateFlag] = useState();
useEffect(() => { useEffect(() => {
// setDataSource(conversationsList); setDataSource(conversationsList);
setDataSource(activeList ? conversationsList: closedConversationsList); // setDataSource(activeList ? conversationsList: closedConversationsList);
return () => {}; return () => {};
}, [conversationsList, listUpdateFlag, currentConversation.unread_msg_count]); }, [conversationsList, listUpdateFlag, currentConversation.unread_msg_count]);
@ -147,9 +199,6 @@ const Conversations = () => {
// switchConversation(item); // switchConversation(item);
}; };
const [{ search: searchContent, ...filter }, setSearchContent] =
useConversationStore((state) => [state.filter, state.setFilterSearch])
const searchInputRef = useRef(null); const searchInputRef = useRef(null);
const [newChatModalVisible, setNewChatModalVisible] = useState(false); const [newChatModalVisible, setNewChatModalVisible] = useState(false);
@ -157,12 +206,13 @@ const Conversations = () => {
// const closedVisible = closedConversationsList.length > 0; // const closedVisible = closedConversationsList.length > 0;
const toggleClosedConversationsList = () => { const toggleClosedConversationsList = () => {
const _active = activeList;
setDataSource(_active ? closedConversationsList : conversationsList);
setActiveList(!activeList); setActiveList(!activeList);
setCurrentConversation({}); setCurrentConversation({});
}; };
const [searchInput, setSearchInput] = useState(searchContent);
return ( return (
<div className='flex flex-col h-inherit'> <div className='flex flex-col h-inherit'>
<div className='flex gap-1 items-center'> <div className='flex gap-1 items-center'>
@ -181,49 +231,36 @@ const Conversations = () => {
className='' className=''
ref={searchInputRef} ref={searchInputRef}
allowClear allowClear
value={searchContent} value={searchInput}
onChange={(e) => { onChange={(e) => {
setSearchContent(e.target.value) setSearchInput(e.target.value)
setTabCnt(-1) // setTabCnt(-1)
setTabSelectedConversation({}) // setTabSelectedConversation({})
}}
onKeyDown={(e) => {
if (e.key === 'Tab') {
e.preventDefault()
const _this = tabCnt >= dataSource.length - 1 ? 0 : tabCnt + 1
setTabCnt(_this)
setTabSelectedConversation(dataSource[_this])
}
}} }}
// onKeyDown={(e) => {
// if (e.key === 'Tab') {
// e.preventDefault()
// const _this = tabCnt >= dataSource.length - 1 ? 0 : tabCnt + 1
// setTabCnt(_this)
// setTabSelectedConversation(dataSource[_this])
// }
// }}
onPressEnter={(e) => { onPressEnter={(e) => {
searchInputRef.current.blur() // searchInputRef.current.blur()
onSwitchConversation(dataSource[tabCnt < 0 ? 0 : tabCnt]) setSearchContent(e.target.value)
setTabCnt(-1) // onSwitchConversation(dataSource[tabCnt < 0 ? 0 : tabCnt])
setTabSelectedConversation({}) // setTabCnt(-1)
// setTabSelectedConversation({})
return false return false
}} }}
placeholder={`名称/号码/订单号${ onSearch={(v, e, { source }) => setSearchContent(v)}
conversationsListLoading ? '...' : '' placeholder={`名称/号码/订单号${conversationsListLoading ? '...' : ''}`}
}`}
// onSearch={handleRichSearchConvs}
// addonBefore={filterTag} // addonBefore={filterTag}
// addonBefore={<FilterOutlined />} // addonBefore={<FilterOutlined />}
// enterButton={'Filter'} // enterButton={'Filter'}
/> />
<Tooltip <Tooltip key={'conversation-list'} title={activeList ? '隐藏会话' : '活跃会话'}>
key={'conversation-list'} <Button onClick={toggleClosedConversationsList} icon={activeList ? <HistoryOutlined className='text-neutral-500' /> : <FireOutlined className=' text-orange-500' />} type='text' />
title={activeList ? '历史会话' : '活跃会话'}>
<Button
onClick={toggleClosedConversationsList}
icon={
activeList ? (
<HistoryOutlined className='text-neutral-500' />
) : (
<FireOutlined className=' text-orange-500' />
)
}
type='text'
/>
</Tooltip> </Tooltip>
{mobile && ( {mobile && (
<AudioTwoTone <AudioTwoTone
@ -233,29 +270,46 @@ const Conversations = () => {
/> />
)} )}
</div> </div>
<ChatListFilter onFilterChange={(list) => setDataSource(list)} activeList={activeList} /> <ChatListFilter
onFilterChange={(d) => {
refreshConversationList()
}}
activeList={activeList}
/>
<div className='flex-1 overflow-x-hidden overflow-y-auto relative'> <div className='flex-1 overflow-x-hidden overflow-y-auto relative'>
{conversationsListLoading && dataSource.length === 0 ? ( {/* {mobile && conversationsListLoading && dataSource.length === 0 ? ( */}
{conversationsListLoading && currentLoading ? (
<div className='text-center py-2'> <div className='text-center py-2'>
<LoadingOutlined className='text-primary ' /> <LoadingOutlined className='text-primary ' />
</div> </div>
) : null} ) : null}
{dataSource.map((item) => ( <List
<ChatListItem itemLayout='vertical'
key={item.sn} dataSource={dataSource}
{...{ loadMore={
item, <div className='text-center pt-3 mb-3 h-8 leading-8 '>
refreshConversationList, {!conversationsListLoading && loadNextPage ? (
setListUpdateFlag, <Button onClick={() => refreshConversationList(false, true)} size='small'>load more</Button>
onSwitchConversation, ) : null}
tabSelectedConversation, {conversationsListLoading && <LoadingOutlined className='text-primary ' />}
setNewChatModalVisible, </div>
setEditingChat, }
}} renderItem={(item, index) => (
/> <ChatListItem
))} key={item.sn}
{dataSource.length === 0 && <Empty description={'无数据'} />} {...{
item,
refreshConversationList,
setListUpdateFlag,
onSwitchConversation,
tabSelectedConversation,
setNewChatModalVisible,
setEditingChat,
}}
/>
)}
/>
</div> </div>
<ConversationsNewItem <ConversationsNewItem
initialValues={{ ...editingChat, is_current_order: false }} initialValues={{ ...editingChat, is_current_order: false }}

Loading…
Cancel
Save