You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
201 lines
6.6 KiB
JavaScript
201 lines
6.6 KiB
JavaScript
import ErrorBoundary from '@/components/ErrorBoundary'
|
|
import useAuthStore from '@/stores/AuthStore'
|
|
import { useThemeContext } from '@/stores/ThemeContext'
|
|
import useConversationStore from '@/stores/ConversationStore'
|
|
import {
|
|
App as AntApp,
|
|
ConfigProvider,
|
|
Empty,
|
|
Modal,
|
|
message,
|
|
FloatButton,
|
|
theme,
|
|
} from 'antd'
|
|
import { AudioOutlined, AudioTwoTone, BugOutlined, CustomerServiceOutlined } from '@ant-design/icons'
|
|
import zhLocale from 'antd/locale/zh_CN'
|
|
import 'dayjs/locale/zh-cn'
|
|
import { useEffect } from 'react'
|
|
import { Link, NavLink, Outlet, useHref, useNavigate } from 'react-router-dom'
|
|
import { appendRequestHeader } from '@/utils/request'
|
|
import { loadPageSpy } from '@/utils/pagespy'
|
|
|
|
import AppLogo from '@/assets/highlights_travel_300_300.png'
|
|
import '@/assets/App.css'
|
|
import 'react-chat-elements/dist/main.css'
|
|
import EmailFetch from './Conversations/Online/Components/EmailFetch'
|
|
import FetchEmailWorker from './../workers/fetchEmailWorker?worker&url'
|
|
import { readWebsocketLog } from '@/utils/indexedDB'
|
|
import { useGlobalNotify } from '@/hooks/useGlobalNotify'
|
|
import GeneratePaymentDrawer from './Conversations/Online/Components/GeneratePaymentDrawer'
|
|
import GenerateAutoDocDrawer from './Conversations/Online/Components/GenerateAutoDocDrawer'
|
|
|
|
// const fetchEmailWorkerURL = new URL('/src/workers/fetchEmailWorker.js', import.meta.url);
|
|
const fetchEmailWorker = new Worker(FetchEmailWorker, { type: 'module' });
|
|
|
|
|
|
function AuthApp() {
|
|
const navigate = useNavigate()
|
|
|
|
const [messageApi, contextHolder] = message.useMessage()
|
|
|
|
const { colorPrimary, borderRadius } = useThemeContext()
|
|
const [loginUser, sendNotify] = useAuthStore((state) => [
|
|
state.loginUser, state.sendNotify
|
|
])
|
|
|
|
const href = useHref()
|
|
|
|
const [connectWebsocket, fetchInitialData, disconnectWebsocket] =
|
|
useConversationStore((state) => [
|
|
state.connectWebsocket,
|
|
state.fetchInitialData,
|
|
state.disconnectWebsocket,
|
|
])
|
|
|
|
useEffect(() => {
|
|
if (!('Notification' in window)) {
|
|
// alert("This browser does not support desktop notification");
|
|
} else {
|
|
Notification.requestPermission()
|
|
}
|
|
let _fetchEmailWorker;
|
|
if (loginUser.userId > 0) {
|
|
appendRequestHeader('X-User-Id', loginUser.userId)
|
|
loadPageSpy(loginUser.username)
|
|
connectWebsocket(loginUser.userId)
|
|
fetchInitialData(loginUser)
|
|
|
|
_fetchEmailWorker = startEmailInterval(loginUser.userId)
|
|
}
|
|
return () => {
|
|
disconnectWebsocket()
|
|
fetchEmailWorker.postMessage({ command: 'logout' })
|
|
if (_fetchEmailWorker) {
|
|
_fetchEmailWorker.terminate();
|
|
}
|
|
}
|
|
}, [])
|
|
|
|
useGlobalNotify();
|
|
|
|
const startEmailInterval = (userId) => {
|
|
// const fetchEmailWorker = new Worker(fetchEmailWorkerURL, { type: 'module' });
|
|
fetchEmailWorker.onerror = function(error) {
|
|
console.error('There was an error in the worker', error);
|
|
};
|
|
fetchEmailWorker.onmessage = function(event) {
|
|
// console.log('Received message from worker', event.data, event.message);
|
|
};
|
|
fetchEmailWorker.postMessage({ command: 'fetchEmail', param: { opi_sn: userId } });
|
|
return fetchEmailWorker;
|
|
}
|
|
|
|
const uploadLog = async () => {
|
|
await readWebsocketLog()
|
|
if (window.$pageSpy) {
|
|
// window.$pageSpy.triggerPlugins('onOfflineLog', 'upload')
|
|
try {
|
|
// await window.$harbor.upload() // 上传日志 { clearCache: true, remark: '' }
|
|
// 上传最近 1 小时的日志, 直接upload 所有日志: 413 Payload Too Large
|
|
const now = Date.now()
|
|
await window.$harbor.uploadPeriods({
|
|
startTime: now - 60 * 60000,
|
|
endTime: now,
|
|
})
|
|
messageApi.info('Success')
|
|
// clearWebsocketLog()
|
|
sendNotify()
|
|
} catch (error) {
|
|
messageApi.error('Failure')
|
|
}
|
|
} else {
|
|
messageApi.error('Failure')
|
|
}
|
|
}
|
|
|
|
// 除了路由 /p...以外都需要登陆系统
|
|
const needToLogin = loginUser.userId === -1 && href.indexOf('/p/') === -1
|
|
|
|
const isMobileApp =
|
|
navigator.userAgent.match(
|
|
/(phone|pad|pod|iPhone|iPod|ios|iPad|Android|Mobile|BlackBerry|IEMobile|MQQBrowser|JUC|Fennec|wOSBrowser|BrowserNG|WebOS|Symbian|Windows Phone)/i,
|
|
) !== null
|
|
|
|
const floatButtonLineEnd = isMobileApp ? 0 : 24
|
|
const floatTrigger = isMobileApp ? 'click' : null
|
|
|
|
|
|
useEffect(() => {
|
|
if (needToLogin) {
|
|
navigate('/p/dingding/login?origin_url=' + href)
|
|
}
|
|
// 销毁弹出的确认窗。处理路由前进、后退不能销毁确认对话框的问题
|
|
Modal.destroyAll()
|
|
}, [href])
|
|
|
|
return (
|
|
<ConfigProvider
|
|
theme={{
|
|
token: {
|
|
colorPrimary: colorPrimary,
|
|
borderRadius: borderRadius,
|
|
fontFamily:
|
|
"-apple-system,BlinkMacSystemFont,Roboto,'Helvetica Neue',Arial,'Noto Sans',sans-serif,'Noto Color Emoji','Apple Color Emoji'",
|
|
},
|
|
algorithm: theme.defaultAlgorithm,
|
|
}}
|
|
locale={zhLocale}
|
|
renderEmpty={() => <Empty description={false} />}
|
|
>
|
|
<AntApp>
|
|
<ErrorBoundary>
|
|
<FloatButton.Group
|
|
shape='square'
|
|
placement={'left'}
|
|
trigger={floatTrigger}
|
|
style={{
|
|
insetInlineEnd: floatButtonLineEnd,
|
|
insetBlockEnd: floatButtonLineEnd,
|
|
flexDirection: 'row',
|
|
}}
|
|
icon={<CustomerServiceOutlined />}
|
|
>
|
|
<EmailFetch />
|
|
<FloatButton icon={<BugOutlined />} tooltip={<div>上传日志给研发部</div>} onClick={() => uploadLog()} />
|
|
<FloatButton.BackTop />
|
|
</FloatButton.Group>
|
|
{contextHolder}
|
|
{needToLogin ? <>login...</> : <Outlet />}
|
|
<dialog id="about-dialog" className="border-0">
|
|
<img className="logo" src={AppLogo} alt="logo" />
|
|
<section className="about">
|
|
<h1>销售平台</h1>
|
|
<h2>Sales CRM</h2>
|
|
<p>Haina travel global sales CRM system</p>
|
|
</section>
|
|
<form className="actions flex gap-1" method="dialog">
|
|
<button
|
|
value="cancel"
|
|
className="px-4 py-2 rounded-full border-0"
|
|
>
|
|
Close
|
|
</button>
|
|
<button
|
|
value="install"
|
|
id="install-button"
|
|
className="px-4 py-2 rounded-full border-0 border-transparent bg-indigo-500 text-white"
|
|
>
|
|
Install app
|
|
</button>
|
|
</form>
|
|
</dialog>
|
|
<GeneratePaymentDrawer />
|
|
<GenerateAutoDocDrawer />
|
|
</ErrorBoundary>
|
|
</AntApp>
|
|
</ConfigProvider>
|
|
)
|
|
}
|
|
|
|
export default AuthApp
|