消息筛选: 实时请求; 打开视频播放

dev/email
Lei OT 12 months ago
parent b0a8c149a1
commit 3f36c648f9

@ -0,0 +1,61 @@
import { createContext, useEffect, useState } from 'react';
import {} from 'antd';
import Modal from '@dckj/react-better-modal';
import '@dckj/react-better-modal/dist/index.css';
import { isEmpty } from '@/utils/commons';
const DnDModal = ({ children, open, setOpen, onCancel, initial = {}, title, ...props }) => {
// const [open, setOpen] = useState(false);
function onHandleMove(e) {
console.log(e, '--->>> onHandleMove');
}
function onHandleResize(e) {
console.log(e, '--->>> onHandleResize');
}
function onHandleOk() {
console.log('onOk callback');
}
function onHandleCancel() {
console.log('onCancel callback');
if (typeof onCancel === 'function') {
onCancel();
}
setOpen(false);
}
function onStageChange({ state }) {
console.log(state);
}
return (
<Modal
visible={open}
keyboard={false}
draggable
resizable
mask={false}
maskClosable={false}
// theme='dark'
// className={'!border !border-solid !border-indigo-500 rounded !p-2' }
className='rounded-t rounded-b-none border border-solid border-indigo-300 shadow-heavy '
titleBarClassName='bg-neutral-100 rounded rounded-b-none border-none p-3 font-bold text-slate-600'
contentClassName='p-2'
footerClassName='p-2'
zIndex={2}
initialWidth={initial.width || 680}
initialHeight={initial.height || 600}
initialTop={initial.top}
initialLeft={initial.left || window.innerWidth - 700}
title={title}
minimizeButton={<></>}
onMove={onHandleMove}
onResize={onHandleResize}
onCancel={onHandleCancel}
// onOk={onHandleOk}
onStageChange={onStageChange}
footer={null}>
<>{children}</>
</Modal>
);
};
export default DnDModal;

@ -1,11 +1,15 @@
import { createContext, useEffect, useState } from 'react';
import { Button, Tag, Radio, Popover, Form, Dropdown, Tabs, List, Image, Empty, Avatar, Card } from 'antd';
import { FileSearchOutlined, FilterOutlined, FilterTwoTone } from '@ant-design/icons';
import { FilterIcon, InboxIcon, MailSendIcon, SendPlaneFillIcon, SendPlaneLineIcon } from '@/components/Icons';
import { groupBy, isEmpty, objectMapper, stringToColour } from '@/utils/commons';
import { useEffect, useState } from 'react';
import { App, Button, Popover, Tabs, List, Image, Avatar, Card } from 'antd';
import { FileSearchOutlined, LoadingOutlined } from '@ant-design/icons';
import { InboxIcon, SendPlaneFillIcon } from '@/components/Icons';
import { groupBy, stringToColour } from '@/utils/commons';
import useConversationStore from '@/stores/ConversationStore';
import { useShallow } from 'zustand/react/shallow';
import EmailDetail from './EmailDetail';
import { MESSAGE_PAGE_SIZE, fetchMessagesHistory } from '@/actions/ConversationActions';
import DnDModal from '@/components/DnDModal';
const BIG_PAGE_SIZE = MESSAGE_PAGE_SIZE * 10;
const CalColorStyle = (tag, outerStyle = true) => {
const color = stringToColour(tag);
@ -13,72 +17,143 @@ const CalColorStyle = (tag, outerStyle = true) => {
return { color: `${color}`, ...outerStyleObj };
};
const getVideoName = (vUrl) => {
if ( ! vUrl) return '';
const url = new URL(vUrl);
return url.pathname.split('/').pop();
};
/**
* 消息记录筛选----------------------------------------------------------------------------------------------------
*/
const MessageListFilter = ({ ...props }) => {
const activeMessages = useConversationStore(
useShallow((state) => (state.currentConversation.sn && state.activeConversations[state.currentConversation.sn] ? state.activeConversations[state.currentConversation.sn] : []))
);
const currentConversation = useConversationStore((state) => state.currentConversation);
const { opi_sn: opisn, whatsapp_phone_number: whatsappid } = currentConversation;
const { message: appMessage } = App.useApp();
const LongList = () => {
const LongList = () => {
return <></>;
};
const [loading, setLoading] = useState(false);
const [paramsForMsgList, setParamsForMsgList] = useState({});
const [historyMessages, setHistoryMessages] = useState([]);
const getMessagesPre = async (param) => {
setLoading(true);
const chatItem = { opisn, whatsappid };
const data = await fetchMessagesHistory({ ...chatItem, lasttime: param.pretime, pagedir: 'pre', pagesize: BIG_PAGE_SIZE });
setLoading(false);
setHistoryMessages((prevValue) => [].concat(data, prevValue));
const loadPrePage = !(data.length === 0 || data.length < BIG_PAGE_SIZE);
// if (data.length > 0) {
// setParamsForMsgList({ loadPrePage, pretime: data[0].orgmsgtime });
// }
setParamsForMsgList((preVal) => ({ ...preVal, loadPrePage, pretime: data.length > 0 ? data[0].orgmsgtime : preVal.pretime }));
};
const onLoadMore = async () => {
await getMessagesPre(paramsForMsgList);
};
const loadMore = paramsForMsgList.loadPrePage ? (
<div className='text-center h-8 leading-8'>
{!loading ? (
<Button onClick={onLoadMore} size='small'>
loading more
</Button>
) : (
<LoadingOutlined className='text-primary' />
)}
</div>
) : null;
const handleCopyClick = (url) => {
try {
navigator.clipboard.writeText(url)
appMessage.success('复制成功😀');
} catch (error) {
appMessage.warning('不支持自动复制, 请手动复制');
}
}
useEffect(() => {
if (activeMessages.length > 0) {
setHistoryMessages(activeMessages);
}
const { opi_sn: opisn, whatsapp_phone_number: whatsappid } = currentConversation;
setParamsForMsgList({ loadPrePage: true, pretime: activeMessages.length > 0 ? activeMessages[0].orgmsgtime : '', opisn, whatsappid });
return () => {};
}, [activeMessages, currentConversation.sn]);
const Album = () => {
const data = (activeMessages || []).filter((item) => item.type === 'photo').reverse();
const data = historyMessages.filter((item) => item.type === 'photo').reverse();
const byDate = groupBy(data, (item) => item.localDate.slice(0, 10));
return (
<>
{data.length === 0 && <Empty description={false} />}
<div className='max-h-96 overflow-y-auto'>
<Image.PreviewGroup className='my-4'>
{Object.keys(byDate).map((date, index) => (
<Card size='small' title={date} key={date} className='mb-2'>
<div className='grid grid-cols-5 gap-2 '>
{byDate[date].map((img) => (
<Image className='border object-cover' key={img.data.id} width={100} height={100} src={img.data.uri} />
))}
</div>
</Card>
))}
</Image.PreviewGroup>
</div>
<Image.PreviewGroup className='my-4'>
<List
className='max-h-96 overflow-y-auto'
itemLayout='vertical'
dataSource={Object.keys(byDate)}
loadMore={loadMore}
loading={loading}
renderItem={(date) => (
<List.Item>
<Card size='small' title={date} key={date} className='mb-2'>
<div className='grid grid-cols-5 gap-2 '>
{byDate[date].map((img) => (
<Image className='border object-cover' key={img.data.id} width={100} height={100} src={img.data.uri} />
))}
</div>
</Card>
</List.Item>
)}
/>
</Image.PreviewGroup>
</>
);
};
const Videos = () => {
// todo:
const data = (activeMessages || []).filter((item) => item.type === 'video').reverse();
const data = historyMessages.filter((item) => item.type === 'video').reverse();
const [videoUrl, setVideoUrl] = useState('');
const [openVideoPlay, setOpenVideoPlay] = useState(false);
const handleOpenVideoPlay = (vurl) => {
setVideoUrl(vurl);
setOpenVideoPlay(true);
setOpenPopup(false);
};
return (
<>
{/* {data.length === 0 && <Empty description={false} />}
<div className='grid grid-cols-3 gap-2 max-h-96 overflow-y-auto'>
{data.map((item) => (
<video controls controlsList='nodownload nofullscreen noremoteplayback' preload='metadata' key={item.data.id} className='max-h-24'>
<source src={`${item?.data.videoURL}#t=0.1`} type='video/mp4' />
Your browser does not support HTML video.
</video>
))}
</div> */}
<List
className='max-h-96 overflow-y-auto'
itemLayout='horizontal'
// itemLayout='horizontal'
dataSource={data}
renderItem={(item, index) => (
<List.Item actions={[item.localDate]}>
loadMore={loadMore}
loading={loading}
renderItem={(item) => (
<List.Item
actions={[
<Button key='copyv' onClick={() => handleCopyClick(item.data.videoURL)} type='link' size='small'>
复制🔗
</Button>,
item.localDate,
]}
className='items-center'>
<List.Item.Meta
// avatar={<Avatar src={`https://api.dicebear.com/7.x/miniavs/svg?seed=${index}`} />}
avatar={
<Avatar size='small' style={CalColorStyle(item.sender)}>
{item.senderName}
</Avatar>
}
title={
<a href={item.data.uri} target='_blank' rel='noreferrer'>
<span onClick={() => handleOpenVideoPlay(item?.data.videoURL)}>
{getVideoName(item?.data.videoURL)}
</a>
</span>
}
description={item.text}
/>
@ -86,18 +161,26 @@ const MessageListFilter = ({ ...props }) => {
</List.Item>
)}
/>
<DnDModal open={openVideoPlay} setOpen={setOpenVideoPlay} title={getVideoName(videoUrl)} key='video-player'>
<video controls preload='metadata' width={660}>
<source src={videoUrl} type='video/mp4' />
Your browser does not support HTML video.
</video>
</DnDModal>
</>
);
};
const Audios = () => {
const data = (activeMessages || []).filter((item) => item.type === 'audio').reverse();
const data = historyMessages.filter((item) => item.type === 'audio').reverse();
return (
<>
<List
className='max-h-96 overflow-y-auto'
itemLayout='horizontal'
// itemLayout='horizontal'
dataSource={data}
renderItem={(item, index) => (
loadMore={loadMore}
loading={loading}
renderItem={(item) => (
<List.Item actions={[item.localDate]}>
<List.Item.Meta
avatar={
@ -115,16 +198,21 @@ const MessageListFilter = ({ ...props }) => {
};
const FileList = () => {
const data = (activeMessages || []).filter((item) => item.type === 'file').reverse();
const data = historyMessages.filter((item) => item.type === 'file').reverse();
return (
<>
{/* {data.length === 0 && <Empty />} */}
<List
className='max-h-96 overflow-y-auto'
itemLayout='horizontal'
// itemLayout='horizontal'
dataSource={data}
renderItem={(item, index) => (
<List.Item actions={[item.localDate]}>
loadMore={loadMore}
loading={loading}
renderItem={(item) => (
<List.Item actions={[
<Button key='copyv' onClick={() => handleCopyClick(item.data.uri)} type='link' size='small'>
复制🔗
</Button>,item.localDate]}>
<List.Item.Meta
// avatar={<Avatar src={`https://api.dicebear.com/7.x/miniavs/svg?seed=${index}`} />}
avatar={
@ -148,8 +236,7 @@ const MessageListFilter = ({ ...props }) => {
};
const EmailList = () => {
// todo:
const data = (activeMessages || []).filter((item) => item.type === 'email').reverse();
const data = historyMessages.filter((item) => item.type === 'email').reverse();
const [openEmailDetail, setOpenEmailDetail] = useState(false);
const [emailDetail, setEmailDetail] = useState({});
@ -163,42 +250,39 @@ const MessageListFilter = ({ ...props }) => {
{/* {data.length === 0 && <Empty />} */}
<List
className='max-h-96 overflow-y-auto'
itemLayout='horizontal'
// itemLayout='horizontal'
dataSource={data}
renderItem={({ emailOrigin, ...item }, index) => (
<List.Item actions={[item.localDate]}>
loadMore={loadMore}
loading={loading}
renderItem={({ emailOrigin, ...item }) => (
<List.Item
actions={[item.localDate]}
className='cursor-pointer'
onClick={() => {
onOpenEmail({ emailOrigin, ...item });
setOpenPopup(false);
}}>
<List.Item.Meta
avatar={
item.sender === 'me' ? <SendPlaneFillIcon /> : <InboxIcon className='text-indigo-500' />
item.sender === 'me' ? <SendPlaneFillIcon className='text-primary' /> : <InboxIcon className='text-indigo-500' />
// <Avatar size='small' style={CalColorStyle(item.senderName)}>
// {item.senderName.substring(0, 3)}
// </Avatar>
}
title={
<Button
type='link'
onClick={() => {
onOpenEmail({ emailOrigin, ...item });
setOpenPopup(false);
}}
size='small'
className='px-0'>
{emailOrigin.subject}
</Button>
}
title={emailOrigin.subject}
description={`To: ${emailOrigin.toEmail}`}
/>
{emailOrigin.abstract}
</List.Item>
)}
/>
<EmailDetail open={openEmailDetail} setOpen={setOpenEmailDetail} emailDetail={emailDetail} key={`email-detail-${emailDetail.id}`} />
<EmailDetail open={openEmailDetail} setOpen={setOpenEmailDetail} emailDetail={emailDetail} key={`email-detail-1-${emailDetail.id}`} />
</>
);
};
const [openPopup, setOpenPopup] = useState(false);
// todo:
return (
<>
<Popover

Loading…
Cancel
Save