diff --git a/package.json b/package.json index 08c8fa9..3db6544 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "global-sales", "private": true, - "version": "1.4.10", + "version": "1.5.0-1", "type": "module", "scripts": { "dev": "vite", diff --git a/src/actions/EmailActions.js b/src/actions/EmailActions.js index 1a61f75..42cdcf4 100644 --- a/src/actions/EmailActions.js +++ b/src/actions/EmailActions.js @@ -1,5 +1,5 @@ import { fetchJSON, postForm, postJSON } from '@/utils/request'; -import { API_HOST, API_HOST_V3, DATE_FORMAT, DATEEND_FORMAT, DATETIME_FORMAT, EMAIL_HOST } from '@/config'; +import { API_HOST, API_HOST_V3, DATE_FORMAT, DATEEND_FORMAT, DATETIME_FORMAT, EMAIL_HOST, EMAIL_HOST_v3 } from '@/config'; import { buildTree, groupBy, isEmpty, objectMapper, omitEmpty, uniqWith } from '@/utils/commons'; import { readIndexDB, writeIndexDB } from '@/utils/indexedDB'; import dayjs from 'dayjs'; @@ -208,7 +208,7 @@ export const getMailboxCountAction = async (params = { opi_sn: '' }, update = tr 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 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 => { @@ -220,7 +220,7 @@ export const getMailboxCountAction = async (params = { opi_sn: '' }, update = tr _MapRoot.set(row.key, row) }) const _newRoot = Array.from(_MapRoot.values()) - writeIndexDB([{ key: Number(params.opi_sn), tree: _newRoot }], 'dirs', 'mailbox') + writeIndexDB([{ ...readCacheDir, key: Number(params.opi_sn), tree: _newRoot }], 'dirs', 'mailbox') notifyMailboxUpdate({ type: 'dirs', key: Number(params.opi_sn) }) } @@ -338,7 +338,7 @@ export const getRootMailboxDirAction = async ({ opi_sn = 0, userIdStr = '' } = { 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] || [])] })) + const rootTree = Object.keys(stickyTree).map((opi) => ({ key: Number(opi), tree: [...stickyTree[opi], ...(mailboxDirByOPI?.[opi] || [])], treeTimestamp: Date.now() })) writeIndexDB(rootTree, 'dirs', 'mailbox') const _mapped = groupBy(rootTree, 'key') return _mapped[opi_sn]?.[0]?.tree || [] @@ -348,7 +348,6 @@ export const getRootMailboxDirAction = async ({ opi_sn = 0, userIdStr = '' } = { * 获取邮件列表 * @usage 邮件目录下的邮件列表 * @usage 订单的邮件列表 - * @usage 高级搜索 */ export const queryEmailListAction = async ({ opi_sn = '', pagesize = 10, last_id = '', node = {}, } = {}) => { const _params = { @@ -375,6 +374,20 @@ export const queryEmailListAction = async ({ opi_sn = '', pagesize = 10, last_id return ret; } +export const searchEmailListAction = async ({opi_sn = '', mailboxtype = 'ALL', sender = '', receiver = '', subject = '', content=''}={}) => { + const formData = new FormData() + formData.append('opi_sn', opi_sn) + formData.append('mailboxtype', mailboxtype) + formData.append('sender', sender) + formData.append('receiver', receiver) + formData.append('subject', subject) + // formData.append('content', content) + const { errcode, result } = await postForm(`${API_HOST_V3}/mail_search`, formData) + const ret = errcode === 0 ? result : [] + notifyMailboxUpdate({ type: 'maillist-search-result', query: [sender, receiver, subject].filter(s => s).join(' '), data: ret.map(ele => ({...ele, key: ele.MAI_SN})) }) + return ret; +} + const removeFromCurrentList = async (params) => { const readRow0 = await readIndexDB(params.mai_sn_list[0], 'listrow', 'mailbox') const listKey = readRow0?.data?.listKey || '' @@ -442,7 +455,7 @@ export const getReminderEmailTemplateAction = async (params = { coli_sn: 0, lgc: * @param {boolean} [isDraft=false] - Whether the email is a draft. */ export const saveEmailDraftOrSendAction = async (body, isDraft = false) => { - const url = isDraft !== false ? `${API_HOST_V3}/email_draft_save` : `${EMAIL_HOST}/sendmail`; + const url = isDraft !== false ? `${API_HOST_V3}/email_draft_save` : `${EMAIL_HOST_v3}/sendmail`; const { attaList=[], atta, content, ...bodyData } = body; bodyData.ordertype = 227001; const formData = new FormData(); @@ -476,7 +489,3 @@ export const queryOPIOrderAction = async (params) => { return errcode !== 0 ? [] : result }; -export const queryInMailboxAction = async (params) => { - const { errcode, result } = await fetchJSON(`${API_HOST_V3}/mail_search`, params) - return errcode !== 0 ? [] : result -} diff --git a/src/components/OrderProfile.jsx b/src/components/OrderProfile.jsx index 64478de..2fa2a3c 100644 --- a/src/components/OrderProfile.jsx +++ b/src/components/OrderProfile.jsx @@ -13,7 +13,7 @@ import { } from '@ant-design/icons' import { useEffect, useState } from 'react' -import { Link, useNavigate } from 'react-router-dom' +import { Link } from 'react-router-dom' import { App, Flex, Select, Tooltip, Divider, Typography, Skeleton, Checkbox, Drawer, Button, Form, Input } from 'antd' import { useOrderStore, fetchSetRemindStateAction, OrderLabelDefaultOptions, OrderStatusDefaultOptions, remindStatusOptions } from '@/stores/OrderStore' import { copy, isEmpty } from '@/utils/commons' @@ -21,24 +21,28 @@ import { useShallow } from 'zustand/react/shallow' import useConversationStore from '@/stores/ConversationStore' import useAuthStore from '@/stores/AuthStore' const OrderProfile = ({ coliSN, ...props }) => { - const navigate = useNavigate() const { notification, message } = App.useApp() - const [formComment, formWhatsApp] = Form.useForm() + const [formComment] = Form.useForm() + const [formWhatsApp] = Form.useForm() + const [formExtra] = Form.useForm() const [loading, setLoading] = useState(false) const [openOrderCommnet, setOpenOrderCommnet] = useState(false) const [openWhatsApp, setOpenWhatsApp] = useState(false) + const [openExtra, setOpenExtra] = useState(false) const orderLabelOptions = copy(OrderLabelDefaultOptions) orderLabelOptions.unshift({ value: 0, label: '未设置', disabled: true }) const orderStatusOptions = copy(OrderStatusDefaultOptions) - const [orderDetail, customerDetail, fetchOrderDetail, setOrderPropValue, appendOrderComment] = useOrderStore((s) => [ + const [orderDetail, customerDetail, fetchOrderDetail, setOrderPropValue, appendOrderComment, updateWhatsapp, updateExtraInfo] = useOrderStore((s) => [ s.orderDetail, s.customerDetail, s.fetchOrderDetail, s.setOrderPropValue, s.appendOrderComment, + s.updateWhatsapp, + s.updateExtraInfo, ]) const loginUser = useAuthStore((state) => state.loginUser) @@ -47,8 +51,8 @@ const OrderProfile = ({ coliSN, ...props }) => { const [orderRemindState, setOrderRemindState] = useState(orderDetail.remindstate) useEffect(() => { - setOrderRemindState(orderDetail.remindstate); - }, [orderDetail.remindstate]); + setOrderRemindState(orderDetail.remindstate) + }, [orderDetail.remindstate]) useEffect(() => { if (orderId) { setLoading(true) @@ -119,12 +123,15 @@ const OrderProfile = ({ coliSN, ...props }) => { - {isEmpty(customerDetail.whatsapp_phone_number) ? - setOpenWhatsApp(true)} size='small'>设置 WhatsApp : - - {customerDetail.whatsapp_phone_number} - - } + {isEmpty(customerDetail.whatsapp_phone_number) ? ( + setOpenWhatsApp(true)} size='small'> + 设置 WhatsApp + + ) : ( + + {customerDetail.whatsapp_phone_number} + + )} @@ -227,9 +234,15 @@ const OrderProfile = ({ coliSN, ...props }) => { 附加信息 - {/* - - */} + + { + formExtra.setFieldsValue({ extra: orderDetail.COLI_Introduction }) + setOpenExtra(true) + }} + /> + {orderDetail.COLI_Introduction} @@ -240,7 +253,6 @@ const OrderProfile = ({ coliSN, ...props }) => { initialValues={{ comment: '' }} scrollToFirstError onFinish={(values) => { - console.log('Received values of form: ', values) appendOrderComment(loginUser.userId, orderId, values.comment) .then(() => { notification.success({ @@ -276,15 +288,47 @@ const OrderProfile = ({ coliSN, ...props }) => { initialValues={{ number: '' }} scrollToFirstError onFinish={(values) => { - console.log('Received values of form: ', values) - // appendOrderComment(loginUser.userId, orderId, values.number) + updateWhatsapp(orderId, values.number) .then(() => { notification.success({ message: '温性提示', description: '设置 WhatsApp 成功', }) setOpenWhatsApp(false) - formComment.setFieldsValue({ number: '' }) + formWhatsApp.setFieldsValue({ number: '' }) + }) + .catch((reason) => { + notification.error({ + message: '设置出错', + description: reason.message, + placement: 'top', + duration: 60, + }) + }) + }}> + + + + + + 提交 + + + + + setOpenExtra(false)} open={openExtra}> + { + updateExtraInfo(orderId, values.extra) + .then(() => { + notification.success({ + message: '温性提示', + description: '设置附加信息成功', + }) + setOpenExtra(false) }) .catch((reason) => { notification.error({ @@ -295,8 +339,8 @@ const OrderProfile = ({ coliSN, ...props }) => { }) }) }}> - - + + diff --git a/src/config.js b/src/config.js index 6f6c568..12b2f4b 100644 --- a/src/config.js +++ b/src/config.js @@ -9,7 +9,7 @@ export const API_HOST = 'http://202.103.68.144:8889/v2'; export const API_HOST_V3 = 'http://202.103.68.144:8889/v3'; // export const WS_URL = 'ws://202.103.68.144:8888'; -// export const EMAIL_HOST = 'http://202.103.68.231:888/service-mail'; +export const EMAIL_HOST_v3 = 'http://202.103.68.144:888/service-mail'; // export const WAI_HOST = 'http://47.83.248.120/api/v1'; // 香港服务器 export const WAI_HOST = 'http://47.254.53.81/api/v1'; // 美国服务器 // export const WAI_HOST = 'http://localhost:3031/api/v1'; // 美国服务器 diff --git a/src/hooks/useEmail.js b/src/hooks/useEmail.js index 892ef4c..1628f2b 100644 --- a/src/hooks/useEmail.js +++ b/src/hooks/useEmail.js @@ -1,7 +1,7 @@ import { useState, useEffect, useCallback } from 'react' import { isEmpty, objectMapper, olog, } from '@/utils/commons' import { readIndexDB } from '@/utils/indexedDB' -import { getEmailDetailAction, postResendEmailAction, getSalesSignatureAction, getEmailOrderAction, queryEmailListAction, getReminderEmailTemplateAction, saveEmailDraftOrSendAction, updateEmailAction, getEmailChangesChannel, EMAIL_CHANNEL_NAME } from '@/actions/EmailActions' +import { getEmailDetailAction, postResendEmailAction, getSalesSignatureAction, getEmailOrderAction, queryEmailListAction, searchEmailListAction, getReminderEmailTemplateAction, saveEmailDraftOrSendAction, updateEmailAction, getEmailChangesChannel, EMAIL_CHANNEL_NAME } from '@/actions/EmailActions' import { App } from 'antd' import useConversationStore from '@/stores/ConversationStore'; import { msgStatusRenderMapped } from '@/channel/bubbleMsgUtils'; @@ -132,16 +132,12 @@ export const useEmailDetail = (mai_sn=0, data={}, oid=0, markRead=false) => { } const postEmailSaveOrSend = async (body, isDraft) => { - try { - const { id: savedID } = await saveEmailDraftOrSendAction(body, isDraft) - setMaiSN(savedID) - if (isDraft) { - refresh() - } - return savedID - } catch (error) { - console.error(error); + const { id: savedID } = await saveEmailDraftOrSendAction(body, isDraft) + setMaiSN(savedID) + if (isDraft) { + refresh() } + return savedID }; return { loading, mailData, orderDetail, postEmailResend, postEmailSaveOrSend } @@ -171,6 +167,7 @@ export const useEmailList = (mailboxDirNode) => { const [error, setError] = useState(null) const [isFreshData, setIsFreshData] = useState(false) const [refreshTrigger, setRefreshTrigger] = useState(0) + const [tempBreadcrumb, setTempBreadcrumb] = useState(null); const refresh = useCallback(() => { setRefreshTrigger((prev) => prev + 1) @@ -178,7 +175,7 @@ export const useEmailList = (mailboxDirNode) => { const { OPI_SN: opi_sn, COLI_SN, VKey, VParent, ApplyDate, OrderSourceType, IsTrue } = mailboxDirNode - const markAsRead = useCallback( + const markAsUnread = useCallback( async (sn_list) => { // 优化性能的话,需要更新 mailList 数据, // 但是更新 mailList 会造成页面全部刷新 @@ -194,7 +191,7 @@ export const useEmailList = (mailboxDirNode) => { await updateEmailAction({ opi_sn: opi_sn, mai_sn_list: sn_list, - set: { read: 1 }, + set: { read: 0 }, }) }, [VKey], @@ -242,7 +239,7 @@ export const useEmailList = (mailboxDirNode) => { setIsFreshData(false) return } - + setTempBreadcrumb(null) setLoading(true) setError(null) setIsFreshData(false) @@ -271,10 +268,19 @@ export const useEmailList = (mailboxDirNode) => { getMailList() // --- Setup Internal Event Listener --- const handleInternalUpdate = (event) => { - // console.log(`[useEmailList] Received internal event. `, event.detail) - if (event.detail && event.detail.type === 'listrow') { + // console.log(`🔔[useEmailList] Received internal event. `, event.detail) + if (isEmpty(event.detail)) { + return false; + } + const { type, } = event.detail + if (type === 'listrow') { loadMailListFromCache() } + if (type === 'maillist-search-result') { + const { data, query } = event.detail + setMailList(data) + setTempBreadcrumb([{title: '查找邮件:'+query, iconIndex: 'search'}]); + } } internalEventEmitter.on(EMAIL_CHANNEL_NAME, handleInternalUpdate) @@ -282,11 +288,20 @@ export const useEmailList = (mailboxDirNode) => { const channel = getEmailChangesChannel() const handleMessage = (event) => { // console.log(`[useEmailList] Received channel event. `, event.data) + if (isEmpty(event.data)) { + return false; + } + const { type, } = event.data const cacheKey = isEmpty(COLI_SN) ? `dir-${VKey}` : `order-${VKey}` - if (event.data.type === 'listrow' && cacheKey === event.data.listKey) { + if (type === 'listrow' && cacheKey === event.data.listKey) { // cacheKey 不相同时, 不需要更新; 邮箱目录不相同 loadMailListFromCache(event.data) } + if (type === 'maillist-search-result') { + // 搜索的结果不需要更新所有页面 + // const { data } = event.detail + // setMailList(data) + } } channel.addEventListener('message', handleMessage) @@ -297,7 +312,7 @@ export const useEmailList = (mailboxDirNode) => { } }, [getMailList]) - return { loading, isFreshData, error, mailList, refresh, markAsRead, markAsProcessed, markAsDeleted } + return { loading, isFreshData, error, mailList, tempBreadcrumb, refresh, markAsUnread, markAsProcessed, markAsDeleted } } const orderMailTypes = new Map([ @@ -416,12 +431,12 @@ export const useEmailTemplate = (templateKey, params) => { } export const mailboxSystemDirs = [ - { key: 1, value: 1, label: '收件箱' }, - { key: 2, value: 2, label: '未读邮件' }, - { key: 3, value: 3, label: '已发邮件' }, - { key: 4, value: 4, label: '待发邮件' }, - { key: 5, value: 5, label: '草稿' }, - { key: 6, value: 6, label: '垃圾邮件' }, - { key: 7, value: 7, label: '已处理邮件' }, - ] + { key: 1, value: 1, label: '收件箱' }, + { key: 2, value: 2, label: '未读邮件' }, + { key: 3, value: 3, label: '已发邮件' }, + { key: 4, value: 4, label: '待发邮件' }, + { key: 5, value: 5, label: '草稿' }, + { key: 6, value: 6, label: '垃圾邮件' }, + { key: 7, value: 7, label: '已处理邮件' }, +] diff --git a/src/stores/ConversationStore.js b/src/stores/ConversationStore.js index 83d9974..b74c7e0 100644 --- a/src/stores/ConversationStore.js +++ b/src/stores/ConversationStore.js @@ -197,10 +197,10 @@ const websocketSlice = (set, get) => ({ // 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); - } + // if (!isEmpty(msgRender)) { + // const msgNotify = receivedMsgTypeMapped[resultType].contentToNotify(msgObj); + // addGlobalNotify(msgNotify); + // } return false; } if ([ @@ -238,7 +238,9 @@ const websocketSlice = (set, get) => ({ // }, 60_000); } // 会话表 更新 - if (['session.new', 'session.updated'].includes(resultType)) { + if (['session.new', 'session.updated'].includes(resultType) + && result.webhooksource !== 'email' + ) { const sessionList = receivedMsgTypeMapped[resultType].getMsg(result); addToConversationList(sessionList, 'top'); } diff --git a/src/stores/EmailSlice.js b/src/stores/EmailSlice.js index 30276b6..4974e81 100644 --- a/src/stores/EmailSlice.js +++ b/src/stores/EmailSlice.js @@ -124,7 +124,7 @@ const emailSlice = (set, get) => ({ let isNeedRefresh = refreshNow if (!isEmpty(readCache)) { setMailboxNestedDirsActive(readCache?.tree || []) - isNeedRefresh = refreshNow || Date.now() - readCache.timestamp > 1 * 60 * 60 * 1000 + isNeedRefresh = refreshNow || Date.now() - readCache.treeTimestamp > 1 * 60 * 60 * 1000 // isNeedRefresh = true; // test: 0 } if (isEmpty(readCache) || isNeedRefresh) { @@ -141,7 +141,7 @@ const emailSlice = (set, get) => ({ // 更新数量 updateMailboxCount: async ({ opi_sn }) => { - const { setMailboxNestedDirsActive } = get() + // const { setMailboxNestedDirsActive } = get() await getMailboxCountAction({ opi_sn }) // const readCache = await readIndexDB(Number(opi_sn), 'dirs', 'mailbox') // if (!isEmpty(readCache)) { @@ -150,7 +150,7 @@ const emailSlice = (set, get) => ({ }, async initMailbox({ opi_sn, dei_sn, userIdStr }) { - olog('initMailbox ---- ') + olog('Initialize Mailbox ---- ') const { currentMailboxOPI, setCurrentMailboxOPI, setCurrentMailboxDEI, getOPIEmailDir, setMailboxNestedDirsActive, } = get() createIndexedDBStore(['dirs', 'maillist', 'listrow', 'mailinfo', 'draft'], 'mailbox') setCurrentMailboxOPI(opi_sn) diff --git a/src/stores/OrderStore.js b/src/stores/OrderStore.js index 7cb5608..2e05247 100644 --- a/src/stores/OrderStore.js +++ b/src/stores/OrderStore.js @@ -1,7 +1,7 @@ import { create } from 'zustand' import { devtools } from 'zustand/middleware' -import { fetchJSON, postForm } from '@/utils/request' -import { API_HOST, EMAIL_HOST } from '@/config' +import { fetchJSON, postForm, postJSON } from '@/utils/request' +import { API_HOST, API_HOST_V3, EMAIL_HOST } from '@/config' import { isNotEmpty, prepareUrl, uniqWith } from '@/utils/commons' const initialState = { @@ -11,213 +11,247 @@ const initialState = { lastQuotation: {}, quotationList: [], otherEmailList: [], -}; - -export const useOrderStore = create(devtools((set, get) => ({ - - ...initialState, - drawerOpen: false, - - resetOrderStore: () => set(initialState), - - openDrawer: () => { - set(() => ({ - drawerOpen: true - })) - }, - - closeDrawer: () => { - set(() => ({ - drawerOpen: false - })) - }, - - fetchOrderList: async (formValues, loginUser) => { - let fetchOrderUrl = `${API_HOST}/getwlorder?opisn=${loginUser.userIdStr}&otype=${formValues.type}` - const params = {}; - - if (formValues.type === 'advance') { - fetchOrderUrl = `${API_HOST}/getdvancedwlorder?opisn=${loginUser.userIdStr}`; - const { type, ...formParams } = formValues; - Object.assign(params, formParams) - } - - return fetchJSON(fetchOrderUrl, params) - .then(json => { - if (json.errcode === 0) { - const _result = json.result.map((order) => { return { ...order, key: order.COLI_ID } }) - const _result_unique = uniqWith(_result, (a, b) => a.COLI_SN === b.COLI_SN) - set(() => ({ - orderList: _result_unique, - })) - } else { - throw new Error(json?.errmsg + ': ' + json.errcode) +} + +export const useOrderStore = create( + devtools( + (set, get) => ({ + ...initialState, + drawerOpen: false, + + resetOrderStore: () => set(initialState), + + openDrawer: () => { + set(() => ({ + drawerOpen: true, + })) + }, + + closeDrawer: () => { + set(() => ({ + drawerOpen: false, + })) + }, + + fetchOrderList: async (formValues, loginUser) => { + let fetchOrderUrl = `${API_HOST}/getwlorder?opisn=${loginUser.userIdStr}&otype=${formValues.type}` + const params = {} + + if (formValues.type === 'advance') { + fetchOrderUrl = `${API_HOST}/getdvancedwlorder?opisn=${loginUser.userIdStr}` + const { type, ...formParams } = formValues + Object.assign(params, formParams) } - }) - }, - - fetchOrderDetail: (colisn) => { - return fetchJSON(`${API_HOST}/getorderinfo`, { colisn }) - .then(json => { - if (json.errcode === 0 && json.result.length > 0) { - const orderResult = json.result[0] - set(() => ({ - orderDetail: {...orderResult, coli_sn: colisn }, - customerDetail: orderResult.contact.length > 0 ? orderResult.contact[0] : {}, - // lastQuotation: orderResult.quotes.length > 0 ? orderResult.quotes[0] : {}, - // quotationList: orderResult.quotes, - })) - return { - orderDetail: {...orderResult, coli_sn: colisn }, - customerDetail: orderResult.contact.length > 0 ? orderResult.contact[0] : {}, - // lastQuotation: orderResult.quotes.length > 0 ? orderResult.quotes[0] : {}, - // quotationList: orderResult.quotes, + return fetchJSON(fetchOrderUrl, params).then((json) => { + if (json.errcode === 0) { + const _result = json.result.map((order) => { + return { ...order, key: order.COLI_ID } + }) + const _result_unique = uniqWith(_result, (a, b) => a.COLI_SN === b.COLI_SN) + set(() => ({ + orderList: _result_unique, + })) + } else { + throw new Error(json?.errmsg + ': ' + json.errcode) } - } else { - throw new Error(json?.errmsg + ': ' + json.errcode) - } - }) - - }, - - appendOrderComment: async (opi_sn, coli_sn, comment) => { - const { fetchOrderDetail } = get() - const formData = new FormData() - formData.append('opi_sn', opi_sn) - formData.append('coli_sn', coli_sn) - formData.append('remark', comment) - - return postForm(`${API_HOST}/remark_order`, formData) - .then(json => { - if (json.errcode === 0) { - return fetchOrderDetail(coli_sn) - } else { - throw new Error(json?.errmsg + ': ' + json.errcode) - } - }) - }, - - generatePayment: async (formValues) => { - const formData = new FormData() - formData.append('descriptions', formValues.description) - formData.append('currency', formValues.currency) - formData.append('lgc', formValues.langauge) - formData.append('amount', formValues.amount) - formData.append('coli_id', formValues.orderNumber) - formData.append('ordertype', formValues.orderType) - formData.append('opisn', formValues.userId) - formData.append('paytype', 'SYT') - formData.append('wxzh', 'cht') - formData.append('fq', 0) - formData.append('onlyusa', 0) - formData.append('useyhm', 0) - - return postForm(`${API_HOST}/generate_payment_links`, formData) - .then(json => { - if (json.errcode === 0) { - return json.result - } else { - throw new Error(json?.errmsg + ': ' + json.errcode) - } - }) - }, - - fetchHistoryOrder: (userId, email, whatsappid='') => { - return fetchJSON(`${API_HOST}/query_guest_order`, { opisn: userId, whatsappid, email: email }) - .then(json => { - if (json.errcode === 0) { - return json.result - } else { - throw new Error(json?.errmsg + ': ' + json.errcode) - } - }) - - }, - - importEmailMessage: ({ orderId, orderNumber }) => { - return fetchJSON(`${API_HOST}/generate_email_msg`, { coli_sn: orderId, coli_id: orderNumber }) - .then(json => { - if (json.errcode === 0) { - return json - } else { - throw new Error(json?.errmsg + ': ' + json.errcode) - } - }) - }, - - batchImportEmailMessage: () => { - const { orderList } = get() - - const orderPromiseList = orderList.map(order => { - return new Promise((resolve, reject) => { - fetchJSON(`${API_HOST}/generate_email_msg`, { coli_sn: order.COLI_SN, coli_id: order.COLI_ID }) - .then(json => { - if (json.errcode === 0) { - resolve(json) - } else { - reject(json?.errmsg + ': ' + json.errcode) + }) + }, + + fetchOrderDetail: (colisn) => { + return fetchJSON(`${API_HOST}/getorderinfo`, { colisn }).then((json) => { + if (json.errcode === 0 && json.result.length > 0) { + const orderResult = json.result[0] + set(() => ({ + orderDetail: { ...orderResult, coli_sn: colisn }, + customerDetail: orderResult.contact.length > 0 ? orderResult.contact[0] : {}, + // lastQuotation: orderResult.quotes.length > 0 ? orderResult.quotes[0] : {}, + // quotationList: orderResult.quotes, + })) + return { + orderDetail: { ...orderResult, coli_sn: colisn }, + customerDetail: orderResult.contact.length > 0 ? orderResult.contact[0] : {}, + // lastQuotation: orderResult.quotes.length > 0 ? orderResult.quotes[0] : {}, + // quotationList: orderResult.quotes, } + } else { + throw new Error(json?.errmsg + ': ' + json.errcode) + } + }) + }, + + appendOrderComment: async (opi_sn, coli_sn, comment) => { + const { fetchOrderDetail } = get() + const formData = new FormData() + formData.append('opi_sn', opi_sn) + formData.append('coli_sn', coli_sn) + formData.append('remark', comment) + + return postForm(`${API_HOST}/remark_order`, formData).then((json) => { + if (json.errcode === 0) { + return fetchOrderDetail(coli_sn) + } else { + throw new Error(json?.errmsg + ': ' + json.errcode) + } + }) + }, + + generatePayment: async (formValues) => { + const formData = new FormData() + formData.append('descriptions', formValues.description) + formData.append('currency', formValues.currency) + formData.append('lgc', formValues.langauge) + formData.append('amount', formValues.amount) + formData.append('coli_id', formValues.orderNumber) + formData.append('ordertype', formValues.orderType) + formData.append('opisn', formValues.userId) + formData.append('paytype', 'SYT') + formData.append('wxzh', 'cht') + formData.append('fq', 0) + formData.append('onlyusa', 0) + formData.append('useyhm', 0) + + return postForm(`${API_HOST}/generate_payment_links`, formData).then((json) => { + if (json.errcode === 0) { + return json.result + } else { + throw new Error(json?.errmsg + ': ' + json.errcode) + } + }) + }, + + fetchHistoryOrder: (userId, email, whatsappid = '') => { + return fetchJSON(`${API_HOST}/query_guest_order`, { opisn: userId, whatsappid, email: email }).then((json) => { + if (json.errcode === 0) { + return json.result + } else { + throw new Error(json?.errmsg + ': ' + json.errcode) + } + }) + }, + + importEmailMessage: ({ orderId, orderNumber }) => { + return fetchJSON(`${API_HOST}/generate_email_msg`, { coli_sn: orderId, coli_id: orderNumber }).then((json) => { + if (json.errcode === 0) { + return json + } else { + throw new Error(json?.errmsg + ': ' + json.errcode) + } + }) + }, + + batchImportEmailMessage: () => { + const { orderList } = get() + + const orderPromiseList = orderList.map((order) => { + return new Promise((resolve, reject) => { + fetchJSON(`${API_HOST}/generate_email_msg`, { coli_sn: order.COLI_SN, coli_id: order.COLI_ID }).then((json) => { + if (json.errcode === 0) { + resolve(json) + } else { + reject(json?.errmsg + ': ' + json.errcode) + } + }) }) - }) - }) - - Promise.all(orderPromiseList).then((values) => { - console.log(values); - }) - }, - - fetchOtherEmail: (coli_sn) => { - return fetchJSON(`${EMAIL_HOST}/email_supplier`, { coli_sn }) - .then(json => { - if (json.errcode === 0) { - set(() => ({ - otherEmailList: json.result.MailInfo ?? [], + }) + + Promise.all(orderPromiseList).then((values) => { + console.log(values) + }) + }, + + fetchOtherEmail: (coli_sn) => { + return fetchJSON(`${EMAIL_HOST}/email_supplier`, { coli_sn }).then((json) => { + if (json.errcode === 0) { + set(() => ({ + otherEmailList: json.result.MailInfo ?? [], + })) + } else { + throw new Error(json?.errmsg + ': ' + json.errcode) + } + }) + }, + + updateWhatsapp: (coli_sn, number) => { + return postJSON(`${API_HOST_V3}/order_update`, { + coli_sn: coli_sn, + set: { + concat_whatsapp: number, + }, + }).then((json) => { + if (json.errcode > 0) { + throw new Error(json?.errmsg + ': ' + json.errcode) + } else { + set((state) => ({ + customerDetail: { + ...state.customerDetail, + whatsapp_phone_number: number, + }, + })) + } + }) + }, + + updateExtraInfo: (coli_sn, extra) => { + const { orderDetail } = get() + + return postJSON(`${API_HOST_V3}/order_update`, { + coli_sn: coli_sn, + set: { + extra_info: extra, + }, + }).then((json) => { + if (json.errcode > 0) { + throw new Error(json?.errmsg + ': ' + json.errcode) + } else { + set((state) => ({ + orderDetail: { + ...state.orderDetail, + COLI_Introduction: extra, + }, + })) + } + }) + }, + + setOrderPropValue: async (colisn, propName, value) => { + if (propName === 'orderlabel') { + set((state) => ({ + orderDetail: { + ...state.orderDetail, + tags: value, + }, })) - } else { - throw new Error(json?.errmsg + ': ' + json.errcode) - } - }) - }, - - setOrderPropValue: async (colisn, propName, value) => { - - if (propName === 'orderlabel') { - set((state) => ({ - orderDetail: { - ...state.orderDetail, - tags: value - } - })) - } - - if (propName === 'orderstatus') { - set((state) => ({ - orderDetail: { - ...state.orderDetail, - states: value } - })) - } - return fetchJSON(`${API_HOST}/setorderstatus`, { colisn, stype: propName, svalue: value }) - .then(json => { - if (json.errcode > 0) { - throw new Error(json?.errmsg + ': ' + json.errcode) + if (propName === 'orderstatus') { + set((state) => ({ + orderDetail: { + ...state.orderDetail, + states: value, + }, + })) } - }) - }, -}), { name: 'orderStore' })) + return fetchJSON(`${API_HOST}/setorderstatus`, { colisn, stype: propName, svalue: value }).then((json) => { + if (json.errcode > 0) { + throw new Error(json?.errmsg + ': ' + json.errcode) + } + }) + }, + }), + { name: 'orderStore' }, + ), +) export const OrderLabelDefaultOptions = [ { value: 240003, label: '重点', emoji: '❣️' }, { value: 240002, label: '次重点', emoji: '❗' }, - { value: 240001, label: '一般', emoji: '' } + { value: 240001, label: '一般', emoji: '' }, ] export const OrderLabelDefaultOptionsMapped = OrderLabelDefaultOptions.reduce((acc, cur) => { return { ...acc, [String(cur.value)]: cur } -}, {}) ; +}, {}) export const OrderStatusDefaultOptions = [ { value: 1, label: '新订单', emoji: '' }, @@ -227,7 +261,7 @@ export const OrderStatusDefaultOptions = [ { value: 5, label: '成行', emoji: '💰' }, { value: 6, label: '丢失', emoji: '🎈' }, { value: 7, label: '取消', emoji: '🚫' }, - { value: 8, label: '未报价', emoji: '' } + { value: 8, label: '未报价', emoji: '' }, ] export const OrderStatusDefaultOptionsMapped = OrderStatusDefaultOptions.reduce((acc, cur) => { return { ...acc, [String(cur.value)]: cur } @@ -239,7 +273,7 @@ export const OrderStatusDefaultOptionsMapped = OrderStatusDefaultOptions.reduce( export const RemindStateDefaultOptions = [ { value: '1', label: '一催' }, { value: '2', label: '二催' }, - { value: '3', label: '三催' } + { value: '3', label: '三催' }, ] /** @@ -251,15 +285,15 @@ export const remindStatusOptions = [ { value: 3, label: '已发三催' }, { value: 'important', label: '重点团' }, { value: 'sendsurvey', label: '已发 travel advisor survey' }, -]; +] export const remindStatusOptionsMapped = remindStatusOptions.reduce((acc, cur) => { return { ...acc, [String(cur.value)]: cur } -}, {}); +}, {}) /** * @param {Object} params { coli_sn, remindstate } */ export const fetchSetRemindStateAction = async (params) => { - const { errcode, result } = await fetchJSON(`${API_HOST}/SetRemindState`, params); - return errcode === 0 ? result : {}; -}; + const { errcode, result } = await fetchJSON(`${API_HOST}/SetRemindState`, params) + return errcode === 0 ? result : {} +} diff --git a/src/utils/indexedDB.js b/src/utils/indexedDB.js index 9c60007..5d57ec2 100644 --- a/src/utils/indexedDB.js +++ b/src/utils/indexedDB.js @@ -104,7 +104,7 @@ export const clearWebsocketLog = () => { export const createIndexedDBStore = (tables, database) => { var open = indexedDB.open(database, INDEXED_DB_VERSION) open.onupgradeneeded = function () { - console.log('readIndexDB onupgradeneeded', database, ) + // console.log('readIndexDB onupgradeneeded', database, ) var db = open.result // 数据库是否存在 for (const table of tables) { @@ -124,7 +124,7 @@ export const createIndexedDBStore = (tables, database) => { export const writeIndexDB = (rows, table, database) => { var open = indexedDB.open(database, INDEXED_DB_VERSION) open.onupgradeneeded = function () { - console.log('readIndexDB onupgradeneeded', table, ) + // console.log('readIndexDB onupgradeneeded', table, ) var db = open.result // 数据库是否存在 if (!db.objectStoreNames.contains(table)) { @@ -170,7 +170,7 @@ export const readIndexDB = (keys=null, table, database) => { return new Promise((resolve, reject) => { let openRequest = indexedDB.open(database) openRequest.onupgradeneeded = function () { - console.log('readIndexDB onupgradeneeded', table, ) + // console.log('readIndexDB onupgradeneeded', table, ) var db = openRequest.result // 数据库是否存在 if (!db.objectStoreNames.contains(table)) { @@ -208,7 +208,7 @@ export const readIndexDB = (keys=null, table, database) => { // console.log(`💾Found record with key ${key}:`, result); innerResolve([key, result]); // Resolve with [key, data] tuple } else { - console.log(`No record found with key ${key}.`); + // console.log(`No record found with key ${key}.`); innerResolve(void 0); // Resolve with undefined for non-existent keys } }; @@ -241,7 +241,7 @@ export const readIndexDB = (keys=null, table, database) => { // console.log(`💾Found record with key ${keys}:`, result); resolve(result); } else { - console.log(`No record found with key ${keys}.`); + // console.log(`No record found with key ${keys}.`); resolve(); } }; @@ -258,10 +258,10 @@ export const readIndexDB = (keys=null, table, database) => { allData.forEach(item => { resultMap.set(item.key, item); }); - console.log(`💾Found all records:`, resultMap); + // console.log(`💾Found all records:`, resultMap); resolve(resultMap); } else { - console.log(`No records found.`); + // console.log(`No records found.`); resolve(resultMap); // Resolve with an empty Map if no records } }; diff --git a/src/views/Conversations/Online/Components/EmailContent.jsx b/src/views/Conversations/Online/Components/EmailContent.jsx index d4cdf8a..0d66293 100644 --- a/src/views/Conversations/Online/Components/EmailContent.jsx +++ b/src/views/Conversations/Online/Components/EmailContent.jsx @@ -113,7 +113,7 @@ const EmailContent = ({ id, content: MailContent, className='', ...props }) => { return ( - + { const [open, setOpen] = useState(false) diff --git a/src/views/NewEmail.jsx b/src/views/NewEmail.jsx index 2b5a53c..6813f7f 100644 --- a/src/views/NewEmail.jsx +++ b/src/views/NewEmail.jsx @@ -21,7 +21,6 @@ import useSnippetStore from '@/stores/SnippetStore' import PaymentlinkBtn from '@/views/Conversations/Online/Input/PaymentlinkBtn' import { TextIcon } from '@/components/Icons'; import { EMAIL_ATTA_HOST, POPUP_FEATURES } from '@/config'; -import RoosterEditor from '@/components/RoosterEditor'; const {confirm} = Modal; // 禁止上传的附件类型 @@ -47,18 +46,19 @@ const parseHTMLText = (html) => { const parser = new DOMParser() const dom = parser.parseFromString(html, 'text/html') // Replace and with line breaks - Array.from(dom.body.querySelectorAll('br, p')).forEach((el) => { - el.textContent = '\n' + el.textContent - }) + // Array.from(dom.body.querySelectorAll('br, p')).forEach((el) => { + // el.textContent = '' + el.textContent + // }) // Replace with a line of dashes - Array.from(dom.body.querySelectorAll('hr')).forEach((el) => { - el.textContent = '\n------------------------------------------------------------------\n' - }) - return dom.body.textContent || '' + // Array.from(dom.body.querySelectorAll('hr')).forEach((el) => { + // el.innerHTML = '------------------------------------------------------------------' + // }) + const line = '------------------------------------------------------------------' + return line+(dom.body.innerHTML || '') } const generateQuoteContent = (mailData, isRichText = true) => { - const html = `From: ${(mailData.info?.MAI_From || '') + const html = `From: ${(mailData.info?.MAI_From || '') .replace(//g, '>')} Sent: ${ mailData.info?.MAI_SendDate || '' @@ -66,11 +66,11 @@ const generateQuoteContent = (mailData, isRichText = true) => { .replace(//g, '>')}Subject: ${mailData.info?.MAI_Subject || ''}${ mailData.info?.MAI_ContentType === 'text/html' ? mailData.content : mailData.content.replace(/\r\n/g, '') - }` + }` return isRichText ? html : parseHTMLText(html) } -const generateMailContent = (mailData) => `${mailData.content}` +const generateMailContent = (mailData) => mailData.info?.MAI_ContentType === 'text/html' ? `${mailData.content}` : `${mailData.content.replace(/\r\n/g, '')}` /** * 独立窗口编辑器 @@ -200,6 +200,8 @@ const NewEmail = () => { mat_sn: emailAccount?.mat_sn || info?.MAI_MAT_SN || defaultMAT, opi_sn: emailAccount?.opi_sn || info?.MAI_OPI_SN || orderDetail.opi_sn || '', } + const originalContentType = info?.mailType === 'text/html'; + setIsRichText(originalContentType) let readyToInitialContent = ''; let _formValues = {}; @@ -214,7 +216,7 @@ const NewEmail = () => { // 排除草稿: `编辑`有id 的邮件 if (!isEmpty(mailData.info) && !['edit'].includes(pageParam.action)) { - readyToInitialContent = orderPrefix + signatureBody + readyToInitialContent = orderPrefix + '' + signatureBody } switch (pageParam.action) { case 'reply': @@ -226,6 +228,7 @@ const NewEmail = () => { subject: `Re: ${info.MAI_Subject || ''}`, ..._form2 } + readyToInitialContent += generateQuoteContent(mailData, originalContentType) break case 'replyall': _formValues = { @@ -236,6 +239,7 @@ const NewEmail = () => { subject: `Re: ${info.MAI_Subject || ''}`, ..._form2 } + readyToInitialContent += generateQuoteContent(mailData, originalContentType) break case 'forward': _formValues = { @@ -244,6 +248,7 @@ const NewEmail = () => { // coli_sn: pageParam.oid, ..._form2 } + readyToInitialContent += generateQuoteContent(mailData, originalContentType) break case 'edit': _formValues = { @@ -255,7 +260,7 @@ const NewEmail = () => { mai_sn: pageParam.quoteid, ..._form2 } - readyToInitialContent = ''+ generateMailContent(mailData) + readyToInitialContent = 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': @@ -266,8 +271,9 @@ const NewEmail = () => { subject: `${info.MAI_Subject || templateFormValues.subject || ''}`, ..._form2, } - readyToInitialContent = generateMailContent({ content: templateContent.bodycontent || readyToInitialContent || `${signatureBody}` || '' }) - setFileList(mailData.attachments.map(ele => ({ uid: ele.ATI_SN, name: ele.ATI_Name, url: ele.ATI_ServerFile, fullPath: `${EMAIL_ATTA_HOST}${ele.ATI_ServerFile}` }))) + readyToInitialContent = generateMailContent({ content: templateContent.bodycontent || readyToInitialContent || `${signatureBody}` || '' }) + // setFileList(mailData.attachments.map(ele => ({ uid: ele.ATI_SN, name: ele.ATI_Name, url: ele.ATI_ServerFile, fullPath: `${EMAIL_ATTA_HOST}${ele.ATI_ServerFile}` }))) + setIsRichText(true) break default: @@ -342,12 +348,14 @@ const NewEmail = () => { } const handleEditorChange = ({ editorStateJSON, htmlContent, textContent }) => { - // console.log('textContent', textContent); + const _text = textContent.replace(/\r\n/g, '\n').replace(/\n{2,}/g, '\n') + // console.log('textContent---\n', textContent, 'textContent'); // console.log('html', html); setHtmlContent(htmlContent) - setTextContent(textContent) + setTextContent(_text) form.setFieldValue('content', htmlContent) - const { bodyText: abstract } = parseHTMLString(htmlContent, true); + const abstract = _text; + // const { bodyText: abstract } = parseHTMLString(htmlContent, true); // form.setFieldValue('abstract', getAbstract(textContent)) const formValues = omitEmpty(form.getFieldsValue()); if (!isEmpty(formValues)) { @@ -497,8 +505,8 @@ const NewEmail = () => { body.attaList = fileList; // console.log('body', body, '\n', fileList); const values = await form.validateFields() - const preQuoteBody = !['edit', 'new'].includes(pageParam.action) && pageParam.quoteid ? (quoteContent ? quoteContent : generateQuoteContent(mailData, isRichText)) : '' - body.mailcontent = isRichText ? EmailBuilder({ subject: values.subject, content: htmlContent + preQuoteBody }) : textContent + preQuoteBody + // const preQuoteBody = !['edit', 'new'].includes(pageParam.action) && pageParam.quoteid ? (quoteContent ? quoteContent : generateQuoteContent(mailData, isRichText)) : '' + body.mailcontent = isRichText ? EmailBuilder({ subject: values.subject, content: htmlContent }) : textContent body.cc = values.cc || '' body.bcc = values.bcc || '' body.bcc = values.mailtype || '' @@ -518,6 +526,8 @@ const NewEmail = () => { try { // console.log('postSendEmail', body, '\n'); + // console.log('🎈postSendEmail mailContent', body.mailcontent, '\n'); + // throw new Error('test') // return; const mailSavedId = await postEmailSaveOrSend(body, isDraft) form.setFieldsValue({ @@ -603,51 +613,30 @@ const NewEmail = () => { requiredMark={false} // labelCol={{ span: 3 }} > - - }> - 发送 - - - `发件人: ${item?.label || '选择'}`} - variant={'borderless'} - placeholder='发件人: 选择' - className='[&_.ant-select-selection-item]:font-bold [&_.ant-select-selection-placeholder]:font-bold [&_.ant-select-selection-placeholder]:text-black' - classNames={{ popup: { root: 'min-w-60' } }} - /> - - {/* 请选择发件地址 */} - - {orderDetail.order_no} - {templateContent.mailtypeName} - setOpenPlainTextConfirm(false)}> - {/* + + onHandleSaveOrSend()} loading={sendLoading} icon={}> + 发送 + + + `发件人: ${item?.label || '选择'}`} variant={'borderless'} placeholder='发件人: 选择' className='[&_.ant-select-selection-item]:font-bold [&_.ant-select-selection-placeholder]:font-bold [&_.ant-select-selection-placeholder]:text-black' classNames={{popup: {root:'min-w-60'}}} /> + + {/* 请选择发件地址 */} + + {orderDetail.order_no} + {templateContent.mailtypeName} + setOpenPlainTextConfirm(false)}> + {/* 纯文本 */} - {/* } className=' ' >纯文本 */} - - - onHandleSaveOrSend(true)} type='dashed' icon={} size='small' className=''> - 存草稿 - - + {/* } className=' ' >纯文本 */} + + + onHandleSaveOrSend(true)} type='dashed' icon={} size='small' className='' >存草稿 + @@ -724,16 +713,15 @@ const NewEmail = () => { - Hello from RoosterJs in your Ant Design React app!' }onChange={handleEditorChange} /> - {!isEmpty(Number(pageParam.quoteid)) && pageParam.action !== 'edit' && !showQuoteContent && ( + {/* {!isEmpty(Number(pageParam.quoteid)) && pageParam.action!=='edit' && !showQuoteContent && ( - setShowQuoteContent(!showQuoteContent)}> - 显示引用内容 ↓ {/*(不可更改)*/} + { + setShowQuoteContent(!showQuoteContent); + setInitialContent(pre => pre + generateQuoteContent(mailData)) + }}> + 显示引用内容 ↓ - {/* {setMergeQuote(false);setShowQuoteContent(false)}}> - 删除引用内容 - */} )} {showQuoteContent && ( @@ -742,7 +730,7 @@ const NewEmail = () => { className='border-0 outline-none cursor-text' onBlur={(e) => setQuoteContent(`${e.target.innerHTML}`)} dangerouslySetInnerHTML={{ __html: generateQuoteContent(mailData) }}> - )} + )} */} > ) diff --git a/src/views/orders/Follow.jsx b/src/views/orders/Follow.jsx index 6c005ca..bf4f99b 100644 --- a/src/views/orders/Follow.jsx +++ b/src/views/orders/Follow.jsx @@ -175,7 +175,7 @@ function Follow() { : } onClick={() => setCollapsed(!collapsed)} - className={`absolute z-10 rounded-none ${collapsed ? 'right-1 top-36 rounded-l-xl' : 'right-8 top-20 rounded-l'}`} + className={`absolute z-10 rounded-none ${collapsed ? 'right-1 top-20 rounded-l-xl' : 'right-8 top-20 rounded-l'}`} size={collapsed ? 'small' : 'middle'} /> diff --git a/src/views/orders/components/MailBox.jsx b/src/views/orders/components/MailBox.jsx index 176e904..cdd62c2 100644 --- a/src/views/orders/components/MailBox.jsx +++ b/src/views/orders/components/MailBox.jsx @@ -1,48 +1,21 @@ import { useEffect, useState } from 'react' 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' import { MailboxDirIcon } from './MailboxDirIcon' import { AttachmentIcon, MailCheckIcon, MailOpenIcon } from '@/components/Icons' import NewEmailButton from './NewEmailButton' import MailOrderSearchModal from './MailOrderSearchModal' +import MailListSearchModal from './MailListSearchModal' -const { RangePicker } = DatePicker const PAGE_SIZE = 50 // 每页显示条数 const MailBox = ({ mailboxDir, onMailItemClick, ...props }) => { - const DATE_RANGE_PRESETS = [ - { - label: '本周', - value: [dayjs().startOf('w'), dayjs().endOf('w')], - }, - { - label: '上周', - value: [dayjs().startOf('w').subtract(7, 'days'), dayjs().endOf('w').subtract(7, 'days')], - }, - { - label: '本月', - value: [dayjs().startOf('M'), dayjs().endOf('M')], - }, - { - label: '上月', - value: [dayjs().subtract(1, 'M').startOf('M'), dayjs().subtract(1, 'M').endOf('M')], - }, - { - label: '前三月', - value: [dayjs().subtract(2, 'M').startOf('M'), dayjs().endOf('M')], - }, - { - label: '本年', - value: [dayjs().startOf('y'), dayjs().endOf('y')], - }, - ] - const [form] = Form.useForm() + const [selectedItems, setSelectedItems] = useState([]) - const { mailList, loading, error, refresh, markAsRead, markAsProcessed, markAsDeleted } = useEmailList(mailboxDir) + const { mailList, loading, error, tempBreadcrumb, refresh, markAsUnread, markAsProcessed, markAsDeleted, } = useEmailList(mailboxDir) const [pagination, setPagination] = useState({ current: 1, @@ -154,21 +127,13 @@ const MailBox = ({ mailboxDir, onMailItemClick, ...props }) => { - + - } - onClick={() => { - markAsRead(selectedItems.map((item) => item.MAI_SN)).then(() => setSelectedItems([])) - }}> - 已读 - } onClick={() => { - console.info('未读未实现') + markAsUnread(selectedItems.map((item) => item.MAI_SN)).then(() => setSelectedItems([])) }}> 未读 @@ -189,36 +154,12 @@ const MailBox = ({ mailboxDir, onMailItemClick, ...props }) => { 删除 + - - - - - - - - - - - - - - - - 搜索 - - - - - { + items={(tempBreadcrumb || props.breadcrumb).map((bc) => { return { title: ( <> diff --git a/src/views/orders/components/MailListSearchModal.jsx b/src/views/orders/components/MailListSearchModal.jsx new file mode 100644 index 0000000..b05e29f --- /dev/null +++ b/src/views/orders/components/MailListSearchModal.jsx @@ -0,0 +1,75 @@ +import { useState } from 'react' +import { SearchOutlined } from '@ant-design/icons' +import { Button, Modal, Form, Input, Radio } from 'antd' +import { searchEmailListAction } from '@/actions/EmailActions' +import useConversationStore from '@/stores/ConversationStore' + +const MailListSearchModal = ({ ...props }) => { + const [currentMailboxOPI] = useConversationStore((state) => [state.currentMailboxOPI]) + + const [openForm, setOpenForm] = useState(false) + const [formSearch] = Form.useForm() + const [loading, setLoading] = useState(false) + + const onSubmitSearchMailList = async (values) => { + setLoading(true) + await searchEmailListAction({...values, opi_sn: currentMailboxOPI}); + setLoading(false) + setOpenForm(false) + } + return ( + <> + setOpenForm(true)} size='small' icon={}> + 查找邮件 + + setOpenForm(false)} + footer={null} + destroyOnHidden + modalRender={(dom) => ( + onSubmitSearchMailList(values)} + className='[&_.ant-form-item]:m-2'> + {dom} + + )}> + + + + + + + + + + + + + + 查找 + + + > + ) +} +export default MailListSearchModal diff --git a/src/views/orders/components/MailOrderSearchModal.jsx b/src/views/orders/components/MailOrderSearchModal.jsx index 76cef9e..c4a0434 100644 --- a/src/views/orders/components/MailOrderSearchModal.jsx +++ b/src/views/orders/components/MailOrderSearchModal.jsx @@ -1,11 +1,10 @@ -import { createContext, useEffect, useState } from 'react' -import { ReloadOutlined, ReadOutlined, RightOutlined, LeftOutlined, SearchOutlined, MailOutlined } from '@ant-design/icons' -import { Button, Modal, Form, Input, Checkbox, Select, Radio, DatePicker, Divider, Typography, Flex } from 'antd' +import { useState } from 'react' +import { SearchOutlined } from '@ant-design/icons' +import { Button, Modal, Form, Input, Checkbox, Radio, DatePicker, Divider, Typography, Flex } from 'antd' import dayjs from 'dayjs' -import { getEmailDirAction, queryHTOrderListAction, queryInMailboxAction } from '@/actions/EmailActions' +import { getEmailDirAction, queryHTOrderListAction, } from '@/actions/EmailActions' import { isEmpty, objectMapper, pick } from '@/utils/commons' import useConversationStore from '@/stores/ConversationStore' -import { mailboxSystemDirs } from '@/hooks/useEmail' const MailOrderSearchModal = ({ ...props }) => { const [currentMailboxOPI] = useConversationStore((state) => [state.currentMailboxOPI]) @@ -38,7 +37,7 @@ const MailOrderSearchModal = ({ ...props }) => { result = await queryHTOrderListAction({ ...htOrderParams, opi_sn: currentMailboxOPI }) const addToTree = { key: 'search-orders', - title: '搜索结果', + title: '查找订单', iconIndex: 'search', _raw: { COLI_SN: 0, IsTrue: 0 }, children: result.map((o) => ({ @@ -46,7 +45,7 @@ const MailOrderSearchModal = ({ ...props }) => { title: `${o.COLI_ID}`, iconIndex: 13, parent: 'search-orders', - parentTitle: '搜索结果', + parentTitle: '查找订单', parentIconIndex: 'search', _raw: { ...o, VKey: o.COLI_SN, VName: o.COLI_ID, VParent: 'search-orders', IsTrue: 0, ApplyDate: '', OrderSourceType: htOrderParams.sourcetype, parent: 'search-orders' }, })), @@ -60,7 +59,7 @@ const MailOrderSearchModal = ({ ...props }) => { return ( <> setOpen(true)} size='small' icon={}> - 查找 + 查找订单 {
with line breaks - Array.from(dom.body.querySelectorAll('br, p')).forEach((el) => { - el.textContent = '\n' + el.textContent - }) + // Array.from(dom.body.querySelectorAll('br, p')).forEach((el) => { + // el.textContent = '' + el.textContent + // }) // Replace
------------------------------------------------------------------
From: ${(mailData.info?.MAI_From || '') + const html = `From: ${(mailData.info?.MAI_From || '') .replace(//g, '>')} Sent: ${ mailData.info?.MAI_SendDate || '' @@ -66,11 +66,11 @@ const generateQuoteContent = (mailData, isRichText = true) => { .replace(//g, '>')}Subject: ${mailData.info?.MAI_Subject || ''}${ mailData.info?.MAI_ContentType === 'text/html' ? mailData.content : mailData.content.replace(/\r\n/g, '') - }` + }
From: ${(mailData.info?.MAI_From || '') .replace(//g, '>')} Sent: ${ mailData.info?.MAI_SendDate || '' @@ -66,11 +66,11 @@ const generateQuoteContent = (mailData, isRichText = true) => { .replace(//g, '>')}Subject: ${mailData.info?.MAI_Subject || ''}${ mailData.info?.MAI_ContentType === 'text/html' ? mailData.content : mailData.content.replace(/\r\n/g, '') - }` + }
From: ${(mailData.info?.MAI_From || '') .replace(//g, '>')}
Sent: ${ mailData.info?.MAI_SendDate || '' @@ -66,11 +66,11 @@ const generateQuoteContent = (mailData, isRichText = true) => { .replace(//g, '>')}
Subject: ${mailData.info?.MAI_Subject || ''}
${ mailData.info?.MAI_ContentType === 'text/html' ? mailData.content : mailData.content.replace(/\r\n/g, '') - }
${mailData.content.replace(/\r\n/g, '')}
${e.target.innerHTML}