|
|
|
@ -1,24 +1,38 @@
|
|
|
|
|
import { useState, useEffect } from 'react'
|
|
|
|
|
import { App, Button, Divider, Avatar } from 'antd'
|
|
|
|
|
import { LoadingOutlined, ApiOutlined, LeftOutlined, RightOutlined } from '@ant-design/icons';
|
|
|
|
|
import { App, Button, Divider, Avatar, List, Flex, Typography } from 'antd'
|
|
|
|
|
import { LoadingOutlined, ApiOutlined, FilePdfOutlined, FileOutlined, FileWordOutlined, FileExcelOutlined, FileJpgOutlined, FileImageOutlined, FileTextOutlined, FileGifOutlined, GlobalOutlined, FileZipOutlined } from '@ant-design/icons'
|
|
|
|
|
import { EditIcon, ReplyIcon, ResendIcon, ShareForwardIcon } from '@/components/Icons'
|
|
|
|
|
import { isEmpty, TagColorStyle } from '@/utils/commons'
|
|
|
|
|
import EmailEditorPopup from '../Input/EmailEditorPopup'
|
|
|
|
|
import DnDModal from '@/components/DnDModal'
|
|
|
|
|
import useStyleStore from '@/stores/StyleStore'
|
|
|
|
|
import { useEmailDetail, } from '@/hooks/useEmail';
|
|
|
|
|
import { EMAIL_ATTA_HOST } from '@/config';
|
|
|
|
|
import EmailBindFormModal from './EmailBind';
|
|
|
|
|
import EmailContent from './EmailContent';
|
|
|
|
|
import { useEmailDetail } from '@/hooks/useEmail'
|
|
|
|
|
import { EMAIL_ATTA_HOST } from '@/config'
|
|
|
|
|
import EmailBindFormModal from './EmailBind'
|
|
|
|
|
import EmailContent from './EmailContent'
|
|
|
|
|
|
|
|
|
|
const extTypeMapped = {
|
|
|
|
|
txt: { icon: FileTextOutlined },
|
|
|
|
|
zip: { icon: FileZipOutlined, color: '#ffe78f' },
|
|
|
|
|
pdf: { icon: FilePdfOutlined, color: '#ad0b00' },
|
|
|
|
|
doc: { icon: FileWordOutlined, color: '#103f91' },
|
|
|
|
|
docx: { icon: FileWordOutlined, color: '#103f91' },
|
|
|
|
|
xls: { icon: FileExcelOutlined, color: '#0c7d0c' },
|
|
|
|
|
xlsx: { icon: FileExcelOutlined, color: '#0c7d0c' },
|
|
|
|
|
jpg: { icon: FileImageOutlined, color: '#1985ff' },
|
|
|
|
|
png: { icon: FileImageOutlined, color: '#1985ff' },
|
|
|
|
|
gif: { icon: FileGifOutlined, color: '#1985ff' },
|
|
|
|
|
html: { icon: GlobalOutlined, color: '#1985ff' },
|
|
|
|
|
default: { icon: FileOutlined }, // rtf bmp
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* @property {*} emailMsg - 邮件数据. { conversationid, actionId, order_opi, coli_sn, msgOrigin: { from, to, id, email: { subject, mai_sn, } } }
|
|
|
|
|
*/
|
|
|
|
|
const EmailDetailInline = ({ mailID, emailMsg={}, disabled=false, ...props }) => {
|
|
|
|
|
|
|
|
|
|
const EmailDetailInline = ({ mailID, emailMsg = {}, disabled = false, ...props }) => {
|
|
|
|
|
// console.log('emailDetail', emailMsg);
|
|
|
|
|
|
|
|
|
|
const {notification, message} = App.useApp()
|
|
|
|
|
const { notification, message } = App.useApp()
|
|
|
|
|
|
|
|
|
|
const { conversationid, actionId, order_opi, coli_sn } = emailMsg
|
|
|
|
|
const { mai_sn, id } = emailMsg.msgOrigin?.email || emailMsg.msgOrigin || {}
|
|
|
|
@ -43,7 +57,7 @@ const EmailDetailInline = ({ mailID, emailMsg={}, disabled=false, ...props }) =>
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const { loading, mailData, orderDetail, postEmailResend } = useEmailDetail(mailID)
|
|
|
|
|
const [showBindBtn, setShowBindBtn] = useState(false);
|
|
|
|
|
const [showBindBtn, setShowBindBtn] = useState(false)
|
|
|
|
|
useEffect(() => {
|
|
|
|
|
setShowBindBtn(isEmpty(mailData.info?.MAI_COLI_SN))
|
|
|
|
|
return () => {}
|
|
|
|
@ -58,13 +72,19 @@ const EmailDetailInline = ({ mailID, emailMsg={}, disabled=false, ...props }) =>
|
|
|
|
|
// setOpen(false)
|
|
|
|
|
} catch (err) {
|
|
|
|
|
notification.error({
|
|
|
|
|
message: "请求失败",
|
|
|
|
|
message: '请求失败',
|
|
|
|
|
description: err.message,
|
|
|
|
|
placement: "top",
|
|
|
|
|
placement: 'top',
|
|
|
|
|
duration: 3,
|
|
|
|
|
});
|
|
|
|
|
})
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
const FileTypeIcon = ({fileName}) => {
|
|
|
|
|
const ext = fileName.split('.').pop() || 'default';
|
|
|
|
|
const Com = extTypeMapped[ext]?.icon || FileOutlined;
|
|
|
|
|
const color = extTypeMapped[ext]?.color || 'inherit';
|
|
|
|
|
return <Com style={{ color: color }} size={36} />;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* 根据状态, 显示操作
|
|
|
|
@ -73,15 +93,15 @@ const EmailDetailInline = ({ mailID, emailMsg={}, disabled=false, ...props }) =>
|
|
|
|
|
* * 失败: 重发
|
|
|
|
|
* todo: disabled 不显示
|
|
|
|
|
*/
|
|
|
|
|
const ActionBtns = ({className, ...props}) => {
|
|
|
|
|
const ActionBtns = ({ className, ...props }) => {
|
|
|
|
|
const { status } = mailData.info
|
|
|
|
|
|
|
|
|
|
let btns = []
|
|
|
|
|
|
|
|
|
|
// 没有关联订单的邮件`绑定订单`
|
|
|
|
|
if (showBindBtn) {
|
|
|
|
|
btns.push(<EmailBindFormModal key={'bind'} onBoundSuccess={() => setShowBindBtn(false)} {...{conversationid, mai_sn, showBindBtn}} />)
|
|
|
|
|
btns.push(<Divider key='divider1' type='vertical' />);
|
|
|
|
|
btns.push(<EmailBindFormModal key={'bind'} onBoundSuccess={() => setShowBindBtn(false)} {...{ conversationid, mai_sn, showBindBtn }} />)
|
|
|
|
|
btns.push(<Divider key='divider1' type='vertical' />)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
switch (status) {
|
|
|
|
@ -92,90 +112,113 @@ const EmailDetailInline = ({ mailID, emailMsg={}, disabled=false, ...props }) =>
|
|
|
|
|
btns.push(
|
|
|
|
|
<Button key={'reply'} onClick={() => onOpenEditor(emailMsg.msgOrigin, 'reply')} size='small' type='text' icon={<ReplyIcon className='text-indigo-500' />}>
|
|
|
|
|
回复
|
|
|
|
|
</Button>
|
|
|
|
|
</Button>,
|
|
|
|
|
)
|
|
|
|
|
btns.push(
|
|
|
|
|
<Button key={'forward'} onClick={() => onOpenEditor(emailMsg.msgOrigin, 'forward')} size='small' type='text' icon={<ShareForwardIcon className='text-primary' />}>
|
|
|
|
|
转发
|
|
|
|
|
</Button>
|
|
|
|
|
</Button>,
|
|
|
|
|
)
|
|
|
|
|
break
|
|
|
|
|
case 'failed':
|
|
|
|
|
btns.push(
|
|
|
|
|
<Button key={'resend'} onClick={() => handleResend()} size='small' type='text' icon={<ResendIcon className='text-orange-500' />}>
|
|
|
|
|
重发
|
|
|
|
|
</Button>
|
|
|
|
|
</Button>,
|
|
|
|
|
)
|
|
|
|
|
btns.push(
|
|
|
|
|
<Button key={'edit'} onClick={() => onOpenEditor({...(emailMsg.msgOrigin || {}), content: mailData.content}, 'edit')} size='small' type='text' icon={<EditIcon className='text-indigo-500' />}>
|
|
|
|
|
<Button
|
|
|
|
|
key={'edit'}
|
|
|
|
|
onClick={() => onOpenEditor({ ...(emailMsg.msgOrigin || {}), content: mailData.content }, 'edit')}
|
|
|
|
|
size='small'
|
|
|
|
|
type='text'
|
|
|
|
|
icon={<EditIcon className='text-indigo-500' />}>
|
|
|
|
|
编辑
|
|
|
|
|
</Button>
|
|
|
|
|
</Button>,
|
|
|
|
|
)
|
|
|
|
|
break
|
|
|
|
|
default:
|
|
|
|
|
break
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return (
|
|
|
|
|
<div className={`flex justify-end items-center gap-1 w-full ${className || ''}`}>
|
|
|
|
|
{btns}
|
|
|
|
|
</div>
|
|
|
|
|
)
|
|
|
|
|
return <div className={`flex justify-end items-center gap-1 w-full ${className || ''}`}>{btns}</div>
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return (
|
|
|
|
|
<>
|
|
|
|
|
<div className='email-container flex flex-col gap-2 *:p-2 *:rounded-sm *:border-b *:border-gray-200 *:shadow-1md'>
|
|
|
|
|
<div className=' font-bold'>{loading ? <LoadingOutlined className='mr-1' /> : null}{mailData.info?.MAI_Subject || emailMsg?.msgOrigin?.subject}</div>
|
|
|
|
|
|
|
|
|
|
<div>
|
|
|
|
|
<div className={['flex flex-wrap justify-end', window.innerWidth < 600 ? 'flex-col' : 'flex-row '].join(' ')}>
|
|
|
|
|
<div className=' flex-auto basis-0 flex flex-wrap gap-2 mb-2 items-center'>
|
|
|
|
|
<Avatar className='' style={TagColorStyle(mailData.info?.MAI_From, true)}>
|
|
|
|
|
{(mailData.info?.MAI_From || '').substring(0, 1)}
|
|
|
|
|
</Avatar>
|
|
|
|
|
<div className=' flex flex-col '>
|
|
|
|
|
{/* <span className=' font-bold text-base'>{mailData.info?.fromName}</span> */}
|
|
|
|
|
<span className='text-neutral-500 text-wrap break-words break-all '>{mailData.info?.MAI_From}</span>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
<div className=' ml-auto flex flex-col justify-start gap-1 items-end'>
|
|
|
|
|
<ActionBtns />
|
|
|
|
|
<div className='text-xs '>{mailData.info?.MAI_SendDate || emailMsg.localDate}</div>
|
|
|
|
|
<div className='email-container flex flex-col gap-2 *:p-2 *:rounded-sm *:border-b *:border-gray-200 *:shadow-1md'>
|
|
|
|
|
<div className=' font-bold'>
|
|
|
|
|
{loading ? <LoadingOutlined className='mr-1' /> : null}
|
|
|
|
|
{mailData.info?.MAI_Subject || emailMsg?.msgOrigin?.subject}
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
<div>
|
|
|
|
|
<div className={['flex flex-wrap justify-end', window.innerWidth < 600 ? 'flex-col' : 'flex-row '].join(' ')}>
|
|
|
|
|
<div className=' flex-auto basis-0 flex flex-wrap gap-2 mb-2 items-center'>
|
|
|
|
|
<Avatar className='' style={TagColorStyle(mailData.info?.MAI_From, true)}>
|
|
|
|
|
{(mailData.info?.MAI_From || '').substring(0, 1)}
|
|
|
|
|
</Avatar>
|
|
|
|
|
<div className=' flex flex-col '>
|
|
|
|
|
{/* <span className=' font-bold text-base'>{mailData.info?.fromName}</span> */}
|
|
|
|
|
<span className='text-neutral-500 text-wrap break-words break-all '>{mailData.info?.MAI_From}</span>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
<div className=' ml-auto flex flex-col justify-start gap-1 items-end'>
|
|
|
|
|
<ActionBtns />
|
|
|
|
|
<div className='text-xs '>{mailData.info?.MAI_SendDate || emailMsg.localDate}</div>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
<div className='text-sm'>
|
|
|
|
|
<span className='text-neutral-500 pr-2 w-12 inline-block text-justify' style={{ textAlignLast: 'justify' }}>
|
|
|
|
|
收件人
|
|
|
|
|
</span>
|
|
|
|
|
{mailData.info?.MAI_To}
|
|
|
|
|
</div>
|
|
|
|
|
{mailData.info?.MAI_CS && (
|
|
|
|
|
<div className='text-sm'>
|
|
|
|
|
<span className='text-neutral-500 pr-2 w-12 inline-block text-justify' style={{ textAlignLast: 'justify' }}>
|
|
|
|
|
抄送
|
|
|
|
|
</span>
|
|
|
|
|
{mailData.info.MAI_CS}
|
|
|
|
|
</div>
|
|
|
|
|
)}
|
|
|
|
|
{mailData.info?.bcc && (
|
|
|
|
|
<div className='text-sm'>
|
|
|
|
|
<span className='text-neutral-500 pr-2 w-12 inline-block text-justify' style={{textAlignLast: 'justify'}}>收件人</span>
|
|
|
|
|
{mailData.info?.MAI_To}
|
|
|
|
|
<span className='text-neutral-500 pr-2 w-12 inline-block text-justify' style={{ textAlignLast: 'justify' }}>
|
|
|
|
|
密送
|
|
|
|
|
</span>
|
|
|
|
|
{mailData.info.bcc}
|
|
|
|
|
</div>
|
|
|
|
|
{mailData.info?.MAI_CS && (
|
|
|
|
|
<div className='text-sm'>
|
|
|
|
|
<span className='text-neutral-500 pr-2 w-12 inline-block text-justify' style={{textAlignLast: 'justify'}}>抄送</span>
|
|
|
|
|
{mailData.info.MAI_CS}
|
|
|
|
|
</div>
|
|
|
|
|
)}
|
|
|
|
|
{mailData.info?.bcc && (
|
|
|
|
|
<div className='text-sm'>
|
|
|
|
|
<span className='text-neutral-500 pr-2 w-12 inline-block text-justify' style={{textAlignLast: 'justify'}}>密送</span>
|
|
|
|
|
{mailData.info.bcc}
|
|
|
|
|
</div>
|
|
|
|
|
)}
|
|
|
|
|
<Divider className='my-2' />
|
|
|
|
|
<Flex className=' divide-y-0 divide-x divide-gray-200 divide-solid gap-0'>
|
|
|
|
|
{mailData.info?.mailType === 'text/html' ? (
|
|
|
|
|
<EmailContent content={mailData.content} id={mailID} key={mailID} />
|
|
|
|
|
) : (
|
|
|
|
|
<div className='mt-2 whitespace-pre-wrap' dangerouslySetInnerHTML={{ __html: mailData.content }}></div>
|
|
|
|
|
)}
|
|
|
|
|
{mailData.attachments.length > 0 && (
|
|
|
|
|
<div className='mt-2 *:ml-2'>
|
|
|
|
|
<span>共{mailData.attachments.length}个附件</span>
|
|
|
|
|
<div className='flex flex-wrap gap-2'>
|
|
|
|
|
{mailData.attachments.map((atta) => (
|
|
|
|
|
<a href={`${EMAIL_ATTA_HOST}${atta.ATI_ServerFile}`} key={atta.ATI_SN} target='_blank' rel='noreferrer'>
|
|
|
|
|
{atta.ATI_Name}
|
|
|
|
|
</a>
|
|
|
|
|
))}
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
<div className='w-48 overflow-hidden'>
|
|
|
|
|
<span> 附件 ({mailData.attachments.length})</span>
|
|
|
|
|
<List
|
|
|
|
|
dataSource={mailData.attachments || []}
|
|
|
|
|
size='small' className='[&_.ant-list-item]:p-1 [&_.ant-list-item]:justify-start'
|
|
|
|
|
renderItem={(atta) => (
|
|
|
|
|
<List.Item>
|
|
|
|
|
<FileTypeIcon fileName={atta.ATI_Name} />
|
|
|
|
|
<Typography.Text ellipsis={{ tooltip: { title: atta.ATI_Name, placement: 'left' } }} className='text-inherit'>
|
|
|
|
|
<a href={`${EMAIL_ATTA_HOST}${atta.ATI_ServerFile}`} key={atta.ATI_SN} target='_blank' rel='noreferrer'>
|
|
|
|
|
{atta.ATI_Name}
|
|
|
|
|
</a>
|
|
|
|
|
</Typography.Text>
|
|
|
|
|
</List.Item>
|
|
|
|
|
)}
|
|
|
|
|
/>
|
|
|
|
|
</div>
|
|
|
|
|
)}
|
|
|
|
|
<Divider className='my-2' />
|
|
|
|
|
{mailData.info?.mailType === 'text/html' ? <EmailContent content={mailData.content} id={mailID} key={mailID} /> : <div className='mt-2 whitespace-pre-wrap' dangerouslySetInnerHTML={{ __html: mailData.content }}></div>}
|
|
|
|
|
</div>
|
|
|
|
|
</Flex>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
<EmailEditorPopup
|
|
|
|
|
open={openEmailEditor}
|
|
|
|
|
setOpen={setOpenEmailEditor}
|
|
|
|
|