diff --git a/src/actions/EmailActions.js b/src/actions/EmailActions.js index 19eb2de..427e107 100644 --- a/src/actions/EmailActions.js +++ b/src/actions/EmailActions.js @@ -165,7 +165,8 @@ const todoTypes = { } /** * 顾问的邮箱目录 - * @param {object} { opi_sn, year, by_start_date, by_success, important, if_want_book, if_thinking } + * @param {object} params { opi_sn, year, by_start_date, by_success, important, if_want_book, if_thinking } + * @param {boolean} retOrder 是否直接返回订单列表 -- 忽略 */ export const getEmailDirAction = async (params = { opi_sn: '' }, retOrder=false) => { const defaultParams = { opi_sn: 0, year: dayjs().year(), by_start_date: -1, by_success: -1, important: -1, if_want_book: -1, if_thinking: -1 } @@ -177,6 +178,35 @@ 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) => { + const defaultParams = { + opi_sn: 0, + // date1: dayjs().subtract(1, 'year').startOf('year').format(DATE_FORMAT), + date1: dayjs().subtract(180, 'days').format(DATE_FORMAT), + date2: dayjs().format(DATEEND_FORMAT) + } + const { errcode, result } = await fetchJSON(`${API_HOST_V3}/dir_count`, {...defaultParams, ...params}) + const ret = errcode !== 0 ? { [`${params.opi_sn}`]: {} } : { [`${params.opi_sn}`]: result } + // 更新数量 + 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 _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]}); + }) + console.log(_MapDir, '_MapDir') + const _newToUpdate = Array.from(_MapDir.values()); + const _MapRoot = new Map((readCacheDir?.tree || []).map((obj) => [obj.key, obj])) + _newToUpdate.forEach((row) => { + _MapRoot.set(row.key, row) + }) + const _newRoot = Array.from(_MapRoot.values()) + writeIndexDB([{ key: Number(params.opi_sn), tree: _newRoot }], 'dirs', 'mailbox') + } + + return ret; +}; export const getTodoOrdersAction = async (params) => { const opi_arr = params.opisn.split(',') const defaultStickyTree = opi_arr.reduce( @@ -211,7 +241,7 @@ export const getTodoOrdersAction = async (params) => { {}, ) const { errcode, result } = await fetchJSON(`${API_HOST}/getwlorder`, params) - // 取后一个状态, 因此翻转两次 + // 订单重复时, 取后一个状态, 因此翻转两次 const _result_unique = uniqWith(result.reverse(), (a, b) => a.COLI_SN === b.COLI_SN).reverse(); const orderList = errcode === 0 ? _result_unique : [] const byOPI = groupBy(orderList, 'OPI_SN') @@ -286,7 +316,9 @@ 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 mailboxDirByOPI = mailboxDir.reduce((a, c) => ({...a, ...c}), {}); + const mailBoxCount = await Promise.all(userIdStr.split(',').map(_opi => getMailboxCountAction({ opi_sn: _opi }))); + 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] || [])] })) writeIndexDB(rootTree, 'dirs', 'mailbox') const _mapped = groupBy(rootTree, 'key') @@ -304,7 +336,8 @@ export const queryEmailListAction = async ({ opi_sn = '', pagesize = 10, last_id vkey: 0, vparent: 0, order_source_type: 0, - mai_senddate1: dayjs().subtract(1, 'year').startOf('year').format(DATE_FORMAT), + // mai_senddate1: dayjs().subtract(1, 'year').startOf('year').format(DATE_FORMAT), + mai_senddate1: dayjs().subtract(180, 'days').format(DATE_FORMAT), mai_senddate2: dayjs().format(DATEEND_FORMAT), ...omitEmpty({ ...node, diff --git a/src/hooks/useEmail.js b/src/hooks/useEmail.js index 114815a..4eec062 100644 --- a/src/hooks/useEmail.js +++ b/src/hooks/useEmail.js @@ -54,7 +54,7 @@ export const useEmailDetail = (mai_sn=0, data={}, oid=0, markRead=false) => { const refresh = useCallback(() => { setRefreshTrigger(prev => prev + 1); }, []); - console.log(maiSN, 'mailSN', mai_sn) + // console.log(maiSN, 'mailSN', mai_sn) // const [updateMessageItem] = useConversationStore(state => [state.updateMessageItem]); diff --git a/src/stores/ConversationStore.js b/src/stores/ConversationStore.js index b3c747e..83d9974 100644 --- a/src/stores/ConversationStore.js +++ b/src/stores/ConversationStore.js @@ -179,7 +179,7 @@ const websocketSlice = (set, get) => ({ logWebsocket(data, 'I'); // olog('websocket Messages ----', data); // console.log(data); - const { updateMessageItem, sentOrReceivedNewMessage, addGlobalNotify, setWai, addToConversationList } = get(); + const { updateMessageItem, sentOrReceivedNewMessage, addGlobalNotify, setWai, addToConversationList, updateMailboxCount } = get() const { errcode, errmsg, result } = data; if (!result) { @@ -195,6 +195,14 @@ const websocketSlice = (set, get) => ({ const msgRender = receivedMsgTypeMapped[resultType].contentToRender(msgObj); const msgUpdate = receivedMsgTypeMapped[resultType].contentToUpdate(msgObj); // console.log('msgRender msgUpdate', msgRender, msgUpdate); + if (['email.updated', 'email.inbound.received',].includes(resultType)) { + updateMailboxCount({ opi_sn: msgObj.opi_sn }) + if (!isEmpty(msgRender)) { + const msgNotify = receivedMsgTypeMapped[resultType].contentToNotify(msgObj); + addGlobalNotify(msgNotify); + } + return false; + } if ([ 'whatsapp.message.updated', 'message', 'error', 'email.updated', 'wai.message.updated', diff --git a/src/stores/EmailSlice.js b/src/stores/EmailSlice.js index 44a46d6..649683b 100644 --- a/src/stores/EmailSlice.js +++ b/src/stores/EmailSlice.js @@ -1,5 +1,5 @@ -import { getEmailDirAction, getRootMailboxDirAction } from '@/actions/EmailActions' -import { buildTree, isEmpty, sortArrayByOrder } from '@/utils/commons' +import { getEmailDirAction, getMailboxCountAction, getRootMailboxDirAction } from '@/actions/EmailActions' +import { buildTree, isEmpty, olog, sortArrayByOrder } from '@/utils/commons' import { readIndexDB, writeIndexDB, createIndexedDBStore, clean7DaysMailboxLog } from '@/utils/indexedDB'; /** @@ -85,18 +85,14 @@ const emailSlice = (set, get) => ({ setMailboxNestedDirsActive: (dir) => { return set(() => ({ mailboxNestedDirsActive: dir })) }, - updateMailboxNestedDirs: (dirs) => { - const { mailboxNestedDirsActive } = get(); - const keep = mailboxNestedDirsActive.filter((ele) => isEmpty(ele.parent)) - return set(() => ({ mailboxNestedDirsActive: [...keep, ...dirs] })) - }, - addMailboxNestedDirs: dirs => { + updateCurrentMailboxNestedDirs: (dirs) => { const { mailboxNestedDirsActive } = get() const _Map = new Map(mailboxNestedDirsActive.map((obj) => [obj.key, obj])) dirs.forEach((row) => { _Map.set(row.key, row) }) - const _newValue = sortArrayByOrder(Array.from(_Map.values()), 'key', ['search-orders']) + // const _newValue = sortArrayByOrder(Array.from(_Map.values()), 'key', ['search-orders']) + const _newValue = Array.from(_Map.values()) return set(() => ({ mailboxNestedDirsActive: _newValue })) }, @@ -119,33 +115,46 @@ const emailSlice = (set, get) => ({ return set(() => ({ mailboxActiveCOLI: coli })) }, - getOPIEmailDir: async (opi_sn = 0, userIdStr='') => { + getOPIEmailDir: async (opi_sn = 0, userIdStr = '', refreshNow = false) => { // console.log('🌐requesting opi dir', opi_sn, typeof opi_sn) - const { setMailboxNestedDirsActive } = get() + const { setMailboxNestedDirsActive, updateMailboxCount } = get() const readCache = await readIndexDB(Number(opi_sn), 'dirs', 'mailbox') // console.log(readCache); - let isNeedRefresh = false + let isNeedRefresh = refreshNow if (!isEmpty(readCache)) { setMailboxNestedDirsActive(readCache?.tree || []) - isNeedRefresh = Date.now() - readCache.timestamp > 1 * 60 * 60 * 1000 + isNeedRefresh = refreshNow || Date.now() - readCache.timestamp > 1 * 60 * 60 * 1000 // isNeedRefresh = true; // test: 0 } if (isEmpty(readCache) || isNeedRefresh) { // > {4} 更新 - const rootTree = await getRootMailboxDirAction({ opi_sn, userIdStr }) + const rootTree = await getRootMailboxDirAction({ opi_sn, userIdStr: String(userIdStr || opi_sn) }) // console.log('empty', opi_sn, userIdStr, isEmpty(readCache), isNeedRefresh, rootTree); setMailboxNestedDirsActive(rootTree) + } else { + // 只更新数量 + updateMailboxCount({ opi_sn }) } return false }, - async initMailbox({ opi_sn, dei_sn, userId, userIdStr }) { + // 更新数量 + 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 || []) + } + }, + + async initMailbox({ opi_sn, dei_sn, userIdStr }) { + olog('initMailbox ---- ') const { setCurrentMailboxOPI, setCurrentMailboxDEI, getOPIEmailDir } = get() createIndexedDBStore(['dirs', 'maillist', 'listrow', 'mailinfo', 'draft'], 'mailbox') setCurrentMailboxOPI(opi_sn) setCurrentMailboxDEI(dei_sn) - getOPIEmailDir(opi_sn, userIdStr) + getOPIEmailDir(opi_sn, userIdStr, true) }, - }) export default emailSlice diff --git a/src/views/orders/Follow.jsx b/src/views/orders/Follow.jsx index 32e19da..ed60ba5 100644 --- a/src/views/orders/Follow.jsx +++ b/src/views/orders/Follow.jsx @@ -1,7 +1,7 @@ import useAuthStore from '@/stores/AuthStore' import { pick } from '@/utils/commons' import { UnorderedListOutlined, LeftOutlined } from '@ant-design/icons' -import { Flex, Segmented, Tree, Typography, Layout, Splitter, Button, Tooltip } from 'antd' +import { Flex, Segmented, Tree, Typography, Layout, Splitter, Button, Tooltip, Badge } from 'antd' import { useEffect, useMemo, useState } from 'react' import EmailDetailInline from '../Conversations/Online/Components/EmailDetailInline' import OrderProfile from '@/components/OrderProfile' @@ -134,11 +134,13 @@ function Follow() {
- } - titleRender={(node) => {node.title}} + titleRender={(node) => ( + + {node.title} + + + )} />
@@ -163,9 +170,14 @@ function Follow() { - -