feat: 邮件: 删除; perf: 更新数量

dev/ckeditor
Lei OT 2 weeks ago
parent d9686b3ef5
commit aabc409f6d

@ -14,6 +14,25 @@ export const parseHTMLString = (html, needText = false) => {
return needText ? { html, bodyContent, bodyText } : bodyContent
}
export const EMAIL_CHANNEL_NAME = 'mailbox_changes';
let emailChangesChannel = null;
export function getEmailChangesChannel() {
if (!emailChangesChannel) {
emailChangesChannel = new BroadcastChannel(EMAIL_CHANNEL_NAME)
}
return emailChangesChannel
}
// 通知邮件列表数据更新
const notifyMailboxUpdate = (payload) => {
const notificationPayload = payload
// - 多个tab
const channel = getEmailChangesChannel()
channel.postMessage(notificationPayload)
// - 当前tab
internalEventEmitter.emit(EMAIL_CHANNEL_NAME, notificationPayload)
}
/**
* 获取顾问签名
* @param {object} { opi_sn }
@ -178,7 +197,7 @@ export const getEmailDirAction = async (params = { opi_sn: '' }, retOrder=false)
const orderList = groupBy(result, row => `${row.IsTrue}`)?.['0'] || [];
return retOrder !== false ? orderList : { [`${params.opi_sn}`]: retTree }
};
export const getMailboxCountAction = async (params = { opi_sn: '' }, update = false) => {
export const getMailboxCountAction = async (params = { opi_sn: '' }, update = true) => {
const defaultParams = {
opi_sn: 0,
// date1: dayjs().subtract(1, 'year').startOf('year').format(DATE_FORMAT),
@ -190,7 +209,7 @@ export const getMailboxCountAction = async (params = { opi_sn: '' }, update = fa
// 更新数量
if (update !== false) {
const readCacheDir = await readIndexDB(Number(params.opi_sn), 'dirs', 'mailbox');
const mailboxDir = isEmpty(readCacheDir) ? [] : readCacheDir.tree.filter(node => node._raw.IsTrue === 1);
const mailboxDir = isEmpty(readCacheDir) ? [] : readCacheDir.tree.filter(node => node?._raw?.IsTrue === 1);
const _MapDir = new Map(mailboxDir.map((obj) => [obj.key, obj]))
Object.keys(result).map(dirKey => {
_MapDir.set(Number(dirKey), {..._MapDir.get(Number(dirKey)), count: result[dirKey]});
@ -202,6 +221,7 @@ export const getMailboxCountAction = async (params = { opi_sn: '' }, update = fa
})
const _newRoot = Array.from(_MapRoot.values())
writeIndexDB([{ key: Number(params.opi_sn), tree: _newRoot }], 'dirs', 'mailbox')
notifyMailboxUpdate({ type: 'dirs', key: Number(params.opi_sn) })
}
return ret;
@ -315,7 +335,7 @@ export const getRootMailboxDirAction = async ({ opi_sn = 0, userIdStr = '' } = {
getTodoOrdersAction({ opisn: userIdStr || String(opi_sn), otype: 'today' }),
...(userIdStr.split(',').map(_opi => getEmailDirAction({ opi_sn: _opi }))),
])
const mailBoxCount = await Promise.all(userIdStr.split(',').map(_opi => getMailboxCountAction({ opi_sn: _opi })));
const mailBoxCount = await Promise.all(userIdStr.split(',').map(_opi => getMailboxCountAction({ opi_sn: _opi }, false)));
const mailboxDirCountByOPI = mailBoxCount.reduce((a, c) => ({ ...a, ...c, }), {})
const mailboxDirByOPI = mailboxDir.reduce((a, c) => ({ ...a, ...(Object.keys(c).reduce((a, opi) => ({...a, [opi]: c[`${opi}`].map((dir) => ({ ...dir, count: mailboxDirCountByOPI[opi][`${dir.key}`] })) }), {} )) }), {})
const rootTree = Object.keys(stickyTree).map((opi) => ({ key: Number(opi), tree: [...stickyTree[opi], ...(mailboxDirByOPI?.[opi] || [])] }))
@ -355,15 +375,16 @@ export const queryEmailListAction = async ({ opi_sn = '', pagesize = 10, last_id
return ret;
}
export const EMAIL_CHANNEL_NAME = 'mailbox_changes';
let emailChangesChannel = null;
export function getEmailChangesChannel() {
if (!emailChangesChannel) {
emailChangesChannel = new BroadcastChannel(EMAIL_CHANNEL_NAME)
const removeFromCurrentList = async (params) => {
const readRow0 = await readIndexDB(params.mai_sn_list[0], 'listrow', 'mailbox')
const listKey = readRow0?.data?.listKey || ''
if (listKey) {
const readCache = await readIndexDB(listKey, 'maillist', 'mailbox')
const updatedMailList = readCache.data.filter((mai_sn) => !params.mai_sn_list.includes(mai_sn))
writeIndexDB([{ key: listKey, data: updatedMailList }], 'maillist', 'mailbox')
notifyMailboxUpdate({ type: 'listrow', listKey, affectKeys: params.mai_sn_list })
}
return emailChangesChannel
}
const updateEmailKeyMap = { read: 'MOI_ReadState' };
const updateEmailKeyFun = {
read: async (params) => {
@ -374,31 +395,13 @@ const updateEmailKeyFun = {
'listrow',
'mailbox',
)
const listKey = readCache.get(params.mai_sn_list[0])?.data?.listKey || '';
// 通知邮件列表数据更新
const listKey = readCache.get(params.mai_sn_list[0])?.data?.listKey || '';
const notificationPayload = { type: 'listrow', listKey, affectKeys: params.mai_sn_list }
// - 多个tab
const channel = getEmailChangesChannel()
channel.postMessage(notificationPayload)
// - 当前tab
internalEventEmitter.emit(EMAIL_CHANNEL_NAME, notificationPayload);
notifyMailboxUpdate(notificationPayload)
},
processed: async (params) => {
const readRow0 = await readIndexDB(params.mai_sn_list[0], 'listrow', 'mailbox')
const listKey = readRow0?.data?.listKey || '';
if (listKey) {
const readCache = await readIndexDB(listKey, 'maillist', 'mailbox')
const updatedMailList = readCache.data.filter(mai_sn => !params.mai_sn_list.includes(mai_sn));
writeIndexDB([{ key: listKey, data: updatedMailList }], 'maillist', 'mailbox')
// 通知邮件列表数据更新
const notificationPayload = { type: 'listrow', listKey, affectKeys: params.mai_sn_list }
// - 多个tab
const channel = getEmailChangesChannel()
channel.postMessage(notificationPayload)
// - 当前tab
internalEventEmitter.emit(EMAIL_CHANNEL_NAME, notificationPayload);
}
}
processed: removeFromCurrentList,
delete: removeFromCurrentList
}
/**
* 更新邮件属性
@ -414,6 +417,7 @@ export const updateEmailAction = async (params = { opi_sn: 0, mai_sn_list: [], s
updateFun(params)
}
}
getMailboxCountAction({ opi_sn: params.opi_sn });
return errcode === 0 ? result : {}
}

@ -201,6 +201,17 @@ export const useEmailList = (mailboxDirNode) => {
[VKey],
)
const markAsDeleted = useCallback(
async (sn_list) => {
await updateEmailAction({
opi_sn: opi_sn,
mai_sn_list: sn_list,
set: { delete: 1 },
})
},
[VKey],
)
const loadMailListFromCache = useCallback(async (payload) => {
const cacheKey = isEmpty(COLI_SN) ? `dir-${VKey}` : `order-${VKey}`
const readCacheIDList = await readIndexDB(cacheKey, 'maillist', 'mailbox')
@ -276,7 +287,7 @@ export const useEmailList = (mailboxDirNode) => {
}
}, [getMailList])
return { loading, isFreshData, error, mailList, refresh, markAsRead, markAsProcessed }
return { loading, isFreshData, error, mailList, refresh, markAsRead, markAsProcessed, markAsDeleted }
}
const orderMailTypes = new Map([

@ -1,6 +1,7 @@
import { getEmailDirAction, getMailboxCountAction, getRootMailboxDirAction } from '@/actions/EmailActions'
import { getEmailDirAction, getMailboxCountAction, getRootMailboxDirAction, getEmailChangesChannel, EMAIL_CHANNEL_NAME } from '@/actions/EmailActions'
import { buildTree, isEmpty, olog, sortArrayByOrder } from '@/utils/commons'
import { readIndexDB, writeIndexDB, createIndexedDBStore, clean7DaysMailboxLog } from '@/utils/indexedDB';
import { internalEventEmitter } from '@/utils/EventEmitterService';
/**
* Email
@ -141,20 +142,43 @@ const emailSlice = (set, get) => ({
// 更新数量
updateMailboxCount: async ({ opi_sn }) => {
const { setMailboxNestedDirsActive } = get()
await getMailboxCountAction({ opi_sn }, true)
const readCache = await readIndexDB(Number(opi_sn), 'dirs', 'mailbox')
if (!isEmpty(readCache)) {
setMailboxNestedDirsActive(readCache?.tree || [])
}
await getMailboxCountAction({ opi_sn })
// const readCache = await readIndexDB(Number(opi_sn), 'dirs', 'mailbox')
// if (!isEmpty(readCache)) {
// setMailboxNestedDirsActive(readCache?.tree || [])
// }
},
async initMailbox({ opi_sn, dei_sn, userIdStr }) {
olog('initMailbox ---- ')
const { setCurrentMailboxOPI, setCurrentMailboxDEI, getOPIEmailDir } = get()
const { currentMailboxOPI, setCurrentMailboxOPI, setCurrentMailboxDEI, getOPIEmailDir, setMailboxNestedDirsActive, } = get()
createIndexedDBStore(['dirs', 'maillist', 'listrow', 'mailinfo', 'draft'], 'mailbox')
setCurrentMailboxOPI(opi_sn)
setCurrentMailboxDEI(dei_sn)
getOPIEmailDir(opi_sn, userIdStr, true)
// --- Setup Internal Event Listener ---
internalEventEmitter.on(EMAIL_CHANNEL_NAME, async (event) => {
console.log(`🔔Received internal event. `, event.detail)
if (event.detail && event.detail.type === 'dirs') {
const readCache = await readIndexDB(event.detail.key, 'dirs', 'mailbox')
if (!isEmpty(readCache)) {
setMailboxNestedDirsActive(readCache?.tree || [])
}
}
})
// --- Setup BroadcastChannel Listener ---
const channel = getEmailChangesChannel()
channel.addEventListener('message', async (event) => {
console.log(`📣Received channel event. `, event.data)
if (event.data.type === 'dirs' && currentMailboxOPI === event.data.key) {
const readCache = await readIndexDB(event.data.key, 'dirs', 'mailbox')
if (!isEmpty(readCache)) {
setMailboxNestedDirsActive(readCache?.tree || [])
}
}
})
},
})
export default emailSlice

@ -245,7 +245,7 @@ const NewEmail = () => {
mai_sn: pageParam.quoteid,
..._form2
}
readyToInitialContent = generateMailContent(mailData)
readyToInitialContent = '<br>'+ generateMailContent(mailData)
setFileList(mailData.attachments.map(ele => ({ uid: ele.ATI_SN, name: ele.ATI_Name, url: ele.ATI_ServerFile, fullPath: `${EMAIL_ATTA_HOST}${ele.ATI_ServerFile}` })))
break
case 'new':

@ -1,6 +1,6 @@
import { useEffect, useState } from 'react'
import { ReloadOutlined, ReadOutlined, RightOutlined, LeftOutlined, SearchOutlined, MailOutlined } from '@ant-design/icons'
import { Flex, Button, Tooltip, List, Form, Row, Col, Input, Checkbox, DatePicker, Switch, Breadcrumb, Skeleton } from 'antd'
import { ReloadOutlined, ReadOutlined, RightOutlined, LeftOutlined, SearchOutlined, MailOutlined, DeleteOutlined } from '@ant-design/icons'
import { Flex, Button, Tooltip, List, Form, Row, Col, Input, Checkbox, DatePicker, Switch, Breadcrumb, Skeleton, Popconfirm } from 'antd'
import dayjs from 'dayjs'
import { useEmailList } from '@/hooks/useEmail'
import { isEmpty } from '@/utils/commons'
@ -42,7 +42,7 @@ const MailBox = ({ mailboxDir, onMailItemClick, ...props }) => {
]
const [form] = Form.useForm()
const [selectedItems, setSelectedItems] = useState([])
const { mailList, loading, error, refresh, markAsRead, markAsProcessed } = useEmailList(mailboxDir)
const { mailList, loading, error, refresh, markAsRead, markAsProcessed, markAsDeleted } = useEmailList(mailboxDir)
const [pagination, setPagination] = useState({
current: 1,
@ -97,6 +97,8 @@ const MailBox = ({ mailboxDir, onMailItemClick, ...props }) => {
const mailItemRender = (item) => {
const isOrderNode = mailboxDir.COLI_SN > 0
const orderNumber = isEmpty(item.MAI_COLI_ID) || isOrderNode ? '' : item.MAI_COLI_ID + ' - '
const folderName = isOrderNode ? `[${item.FDir}]` : ''
const orderMailType = <span className='text-blue-400 text-xs'>{item.MAT_Name}</span>
const countryName = isEmpty(item.CountryCN) ? '' : '[' + item.CountryCN + '] '
const mailStateClass = item.MOI_ReadState === 0 ? 'font-bold' : ''
const hasAtta = item.MAI_Attachment !== 0 ? <AttachmentIcon className='text-blue-500' /> : null
@ -173,6 +175,13 @@ const MailBox = ({ mailboxDir, onMailItemClick, ...props }) => {
markAsProcessed(selectedItems.map((item) => item.MAI_SN)).then(() => setSelectedItems([]))
}}
>已处理</Button>
<Button
size='small' // danger
icon={<DeleteOutlined />}
onClick={() => {
markAsDeleted(selectedItems.map((item) => item.MAI_SN)).then(() => setSelectedItems([]))
}}
>删除</Button>
<MailOrderSearchModal />
</div>
<div className='bg-white h-auto p-1 flex gap-1 items-center hidden'>

Loading…
Cancel
Save