新窗口: 邮件编辑

dev/ckeditor
Lei OT 4 months ago
parent ef3e55eefb
commit e113c33fc6

@ -3,7 +3,7 @@ import { API_HOST, DATE_FORMAT, DATEEND_FORMAT, DATETIME_FORMAT, EMAIL_HOST } fr
import { buildTree, groupBy, isEmpty, objectMapper, omitEmpty, readIndexDB, uniqWith, writeIndexDB } from '@/utils/commons';
import dayjs from 'dayjs';
const parseHTMLString = (html, needText = false) => {
export const parseHTMLString = (html, needText = false) => {
const parser = new DOMParser()
const doc = parser.parseFromString(html, 'text/html')
let bodyContent = doc.body.innerHTML

@ -108,7 +108,7 @@ const emailSlice = (set, get) => ({
if (!isEmpty(readCache)) {
setMailboxNestedDirsActive(readCache?.tree || [])
isNeedRefresh = Date.now() - readCache.timestamp > 4 * 60 * 60 * 1000
isNeedRefresh = true; // test: 0
// isNeedRefresh = true; // test: 0
}
if (isEmpty(readCache) || isNeedRefresh) {
// > {4} 更新
@ -120,7 +120,7 @@ const emailSlice = (set, get) => ({
async initMailbox({ opi_sn, dei_sn, userId, userIdStr }) {
const { setCurrentMailboxOPI, setCurrentMailboxDEI, getOPIEmailDir } = get()
createIndexedDBStore(['dirs', 'maillist', 'mailinfo'], 'mailbox')
createIndexedDBStore(['dirs', 'maillist', 'mailinfo', 'draft'], 'mailbox')
setCurrentMailboxOPI(opi_sn)
setCurrentMailboxDEI(dei_sn)
getOPIEmailDir(userId, userIdStr)

@ -862,7 +862,7 @@ export const readIndexDB = (key=null, table, database) => {
getRequest.onsuccess = (event) => {
const result = event.target.result
if (result) {
console.log(`Found record with key ${key}:`, result)
console.log(`💾Found record with key ${key}:`, result)
resolve(result)
} else {
console.log(`No record found with key ${key}.`)

@ -3,7 +3,6 @@ import { useParams, useNavigate, useLocation } from 'react-router-dom';
import { App, ConfigProvider, Button, Form, Input, Flex, Checkbox, Popconfirm, Select, Space, Upload, Divider, Modal, Tabs, Radio } from 'antd'
import { UploadOutlined, LoadingOutlined, SaveOutlined, SendOutlined, CheckCircleOutlined } from '@ant-design/icons'
import '@dckj/react-better-modal/dist/index.css'
import DnDModal from '@/components/DnDModal'
import useStyleStore from '@/stores/StyleStore'
// import useConversationStore from '@/stores/ConversationStore'
import useAuthStore from '@/stores/AuthStore'
@ -11,9 +10,9 @@ import useAuthStore from '@/stores/AuthStore'
import LexicalEditor from '@/components/LexicalEditor'
import { v4 as uuid } from 'uuid'
import { cloneDeep, debounce, isEmpty, writeIndexDB } from '@/utils/commons'
import { cloneDeep, debounce, isEmpty, writeIndexDB, readIndexDB, deleteIndexDBbyKey } from '@/utils/commons'
import '@/views/Conversations/Online/Input/EmailEditor.css'
import { postSendEmail } from '@/actions/EmailActions'
import { parseHTMLString, postSendEmail } from '@/actions/EmailActions'
import { sentMsgTypeMapped } from '@/channel/bubbleMsgUtils'
import { EmailBuilder, useEmailDetail, useEmailSignature } from '@/hooks/useEmail'
import useSnippetStore from '@/stores/SnippetStore'
@ -74,7 +73,7 @@ const generateMailContent = (mailData) => `<br><br><p>${mailData.content}</p>`
/**
* ! 无状态管理
*/
const NewEmail = ({ ...props }) => {
const NewEmail = () => {
const pageParam = useParams();
const editorKey = pageParam.action==='new' ? `new-${Date.now().toString(32)}` : `${pageParam.action}-${pageParam.quoteid}`
@ -121,18 +120,49 @@ const NewEmail = ({ ...props }) => {
}
const [contentPrefix, setContentPrefix] = useState('')
const [localDraft, setLocalDraft] = useState();
const readMailboxLocalCache = async () => {
const readCache = await readIndexDB(editorKey, 'draft', 'mailbox')
if (readCache) {
const btn = (
<Space>
<Button type='link' size='small' onClick={() => notification.destroy()}>
关闭
</Button>
{/* <Button type="primary" size="small" onClick={() => notification.destroy()}>
Confirm
</Button> */}
</Space>
)
// notification.open({
// key: editorKey,
// placement: 'top',
// // message: '',
// description: '',
// duration: 0,
// actions: btn,
// })
setLocalDraft(readCache);
}
}
useEffect(() => {
readMailboxLocalCache()
return () => {}
}, [])
// const [stickToCid, setStickToCid] = useState(pageParam.conversationid)
useEffect(() => {
console.log('useeffect\n', orderDetail.order_no);
// const propsObj = { ...activeEdit, mai: activeEdit.mailData?.info?.MAI_MAT_SN }
setContentPrefix(orderDetail.order_no ? `<p>Dear Mr./Ms. ${orderDetail.contact?.[0]?.name || ''}</p><p>Reference Number: ${orderDetail.order_no}</p>` : '')
return () => {}
}, [orderDetail.order_no])
}, [orderDetail.order_no, editorKey])
const handleSwitchEmail = (labelValue) => {
const handleSwitchEmail = (labelValue) => {
const { value } = labelValue
setNewFromEmail(value)
const _findMat = emailListAddrMapped?.[value]
@ -162,11 +192,18 @@ const NewEmail = ({ ...props }) => {
setHtmlContent(htmlContent)
setTextContent(textContent)
form.setFieldValue('content', htmlContent)
const { bodyText: abstract } = parseHTMLString(htmlContent, true);
const body = {
from: newFromEmail,
attaList: fileList,
opi_sn: emailOPI,
mat_sn: emailMat,
coli_sn: emailOrder || '',
}
// form.setFieldValue('abstract', getAbstract(textContent))
debouncedSave({ htmlContent, ...form.getFieldsValue() })
debouncedSave({ ...form.getFieldsValue(), ...body, htmlContent, abstract, })
}
const [initialForm, setInitialForm] = useState({})
const [initialContent, setInitialContent] = useState('')
const [showQuoteContent, setShowQuoteContent] = useState(false)
const [mergeQuote, setMergeQuote] = useState(true)
@ -176,9 +213,29 @@ const NewEmail = ({ ...props }) => {
useEffect(() => {
console.log('useEffect 2---- \nform.setFieldsValue ');
const docTitle = localDraft?.subject || mailData.info?.MAI_Subject || 'New Email-';
setTimeout(() => {
document.title = mailData.info?.MAI_Subject || 'New Email-'
document.title = docTitle
}, 1500);
if (!isEmpty(localDraft)) {
const {htmlContent, ...draftFormsValues} = localDraft;
const _findMatOld = emailListMatMapped?.[draftFormsValues.mat_sn]
const _from = draftFormsValues?.from || _findMatOld?.email || ''
form.setFieldsValue(draftFormsValues);
setNewFromEmail(_from);
setEmailOPI(draftFormsValues.opi_sn)
setEmailMat(draftFormsValues.mat_sn)
setEmailOrder(draftFormsValues.coli_sn)
requestAnimationFrame(() => {
setInitialContent(htmlContent);
});
return () => {};
}
//
if (isEmpty(pageParam.quoteid)) {
@ -241,7 +298,6 @@ const NewEmail = ({ ...props }) => {
subject: `Re: ${info.MAI_Subject || ''}`,
}
form.setFieldsValue(_formValues)
setInitialForm(_formValues)
} else if (pageParam.action === 'replyall') {
const _formValues = {
to: info?.replyToAll || newFromEmail,
@ -250,10 +306,8 @@ const NewEmail = ({ ...props }) => {
subject: `Re: ${info.MAI_Subject || ''}`,
}
form.setFieldsValue(_formValues)
setInitialForm(_formValues)
} else if (pageParam.action === 'forward') {
form.setFieldsValue(forwardValues)
setInitialForm(forwardValues)
} else if (pageParam.action === 'edit') {
const thisFormValues = {
to: info?.MAI_To || '',
@ -261,20 +315,19 @@ const NewEmail = ({ ...props }) => {
subject: info?.MAI_Subject || '',
}
form.setFieldsValue(thisFormValues)
setInitialForm(thisFormValues)
const thisBody = generateMailContent(mailData)
// console.log('thisBody', thisBody);
setInitialContent(thisBody)
} else if (pageParam.action === 'new') {
const newEmail = { to: newToEmail, subject: pageParam.draft?.subject || '' }
// todo:
const newEmail = { to: newToEmail, subject: '' }
form.setFieldsValue(newEmail)
setInitialForm(newEmail)
setInitialContent((pageParam.draft?.content || contentPrefix || '') + signatureBody)
setInitialContent((contentPrefix || '') + signatureBody)
}
return () => {}
}, [ mailData.info, signature, newToEmail])
}, [ mailData.info, signature, newToEmail, contentPrefix, localDraft])
const [openPlainTextConfirm, setOpenPlainTextConfirm] = useState(false)
const handlePlainTextOpenChange = ({ target }) => {
@ -463,13 +516,25 @@ const NewEmail = ({ ...props }) => {
bubbleMsg.email.mai_sn = mailSavedId
// console.log('invokeEmailMessage', bubbleMsg);
invokeEmailMessage(bubbleMsg)
// invokeEmailMessage(bubbleMsg)
// setSendLoading(false);
notification.success({
key: editorKey,
message: '成功',
// description: error.message,
placement: 'top',
duration: 2,
onClose: () => {
deleteIndexDBbyKey(editorKey, 'draft', 'mailbox');
window.close();
},
})
// setOpen(false)
} catch (error) {
notification.error({
key: editorKey,
message: '邮件保存失败',
description: error.message,
placement: 'top',
@ -489,7 +554,7 @@ const NewEmail = ({ ...props }) => {
debounce((data) => {
idleCallbackId.current = window.requestIdleCallback(() => {
console.log('Saving data (idle, debounced):', data)
writeIndexDB([{ ...data, key: editorKey }], 'draft', 'EmailEditor')
writeIndexDB([{ ...data, key: editorKey }], 'draft', 'mailbox')
})
}, 1500), // 1.5s
[],
@ -604,7 +669,7 @@ const NewEmail = ({ ...props }) => {
</Form.Item>
</Form>
<LexicalEditor {...{ isRichText }} onChange={handleEditorChange} defaultValue={initialContent} />
{pageParam.quoteid && !showQuoteContent && (
{pageParam.quoteid && pageParam.action!=='edit' && !showQuoteContent && (
<div className='flex justify-start items-center ml-2'>
<Button className='flex gap-2 ' type='link' onClick={() => setShowQuoteContent(!showQuoteContent)}>
显示引用内容 {/*(不可更改)*/}

Loading…
Cancel
Save