|
|
|
import { Outlet, Link, useHref, useNavigate, useLocation, NavLink } from "react-router-dom";
|
|
|
|
import { useEffect, useState } from 'react';
|
|
|
|
import { observer } from "mobx-react";
|
|
|
|
import { toJS } from "mobx";
|
|
|
|
import { Layout, Menu, ConfigProvider, theme, Dropdown, Space, Row, Col, Badge, Typography, Modal, Input, Button, App as AntApp } from "antd";
|
|
|
|
import { DownOutlined } from "@ant-design/icons";
|
|
|
|
import "antd/dist/reset.css";
|
|
|
|
import AppLogo from "@/assets/logo-gh.png";
|
|
|
|
import { isEmpty } from "@/utils/commons";
|
|
|
|
import { useStore } from "@/stores/StoreContext.js";
|
|
|
|
import * as config from "@/config";
|
|
|
|
import Language from "../i18n/LanguageSwitcher";
|
|
|
|
import { useTranslation } from 'react-i18next';
|
|
|
|
import zhLocale from 'antd/locale/zh_CN';
|
|
|
|
import enLocale from 'antd/locale/en_US';
|
|
|
|
import 'dayjs/locale/zh-cn';
|
|
|
|
import { BUILD_VERSION, } from '@/config';
|
|
|
|
|
|
|
|
const { Header, Content, Footer } = Layout;
|
|
|
|
const { Title } = Typography;
|
|
|
|
|
|
|
|
let items = [];
|
|
|
|
|
|
|
|
const useItemDefault = () => {
|
|
|
|
const [data, setData] = useState([]);
|
|
|
|
const { t, i18n } = useTranslation();
|
|
|
|
|
|
|
|
useEffect(() => {
|
|
|
|
const newData = [
|
|
|
|
{ label: <Link to='/account/change-password'>{t('ChangePassword')}</Link>, key: '0' },
|
|
|
|
{ label: <Link to='/account/profile'>{t('Profile')}</Link>, key: '1' },
|
|
|
|
{ type: 'divider' },
|
|
|
|
{ label: <Link to='/login?out'>{t('Logout')}</Link>, key: '3' },
|
|
|
|
];
|
|
|
|
setData(newData);
|
|
|
|
}, [i18n.language]);
|
|
|
|
|
|
|
|
return data;
|
|
|
|
};
|
|
|
|
const useItemManager = () => {
|
|
|
|
const items_default = useItemDefault();
|
|
|
|
const [data, setData] = useState(items_default);
|
|
|
|
const { t, i18n } = useTranslation();
|
|
|
|
|
|
|
|
useEffect(() => {
|
|
|
|
const newData = [
|
|
|
|
{ label: <Link to='/account/change-password'>{t('ChangePassword')}</Link>, key: '0' },
|
|
|
|
{ label: <Link to='/account/profile'>{t('Profile')}</Link>, key: '1' },
|
|
|
|
{ type: 'divider' },
|
|
|
|
{ label: <Link to='/login?out'>{t('Logout')}</Link>, key: '3' },
|
|
|
|
{ label: <Link to='/account/change-vendor'>{t('ChangeVendor')}</Link>, key: '4' },
|
|
|
|
];
|
|
|
|
setData(newData);
|
|
|
|
}, [i18n.language]);
|
|
|
|
return data;
|
|
|
|
};
|
|
|
|
|
|
|
|
function App() {
|
|
|
|
const { t, i18n } = useTranslation();
|
|
|
|
const items_default = useItemDefault();
|
|
|
|
const item_manager = useItemManager();
|
|
|
|
|
|
|
|
const [password, setPassword] = useState('');
|
|
|
|
const { authStore, noticeStore } = useStore();
|
|
|
|
const { notification } = AntApp.useApp();
|
|
|
|
const login = toJS(authStore.login);
|
|
|
|
const { noticeUnRead } = noticeStore;
|
|
|
|
const href = useHref();
|
|
|
|
const loginToken = login.token;
|
|
|
|
const navigate = useNavigate();
|
|
|
|
const location = useLocation();
|
|
|
|
|
|
|
|
const arrManager = config.arrManager; // ["testzp","testzac","testycc","testlyj","testqqs","testjjh","testhn"];//特定账号加修改所属供应商的菜单 zp
|
|
|
|
if (arrManager.includes(authStore.login.username)){
|
|
|
|
items = item_manager;
|
|
|
|
}else{
|
|
|
|
items = items_default;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
useEffect(() => {
|
|
|
|
if (href !== '/login' && isEmpty(loginToken)) {
|
|
|
|
navigate('/login');
|
|
|
|
}
|
|
|
|
}, [href]);
|
|
|
|
|
|
|
|
useEffect(() => {
|
|
|
|
window.gtag('event', 'page_view', { page_location: window.location.href });
|
|
|
|
}, [location]);
|
|
|
|
|
|
|
|
const onSubmit = () => {
|
|
|
|
authStore.valdateUserPassword(login.username, password)
|
|
|
|
.then(() => {
|
|
|
|
authStore.fetchUserDetail()
|
|
|
|
.catch(ex => {
|
|
|
|
notification.error({
|
|
|
|
message: `Notification`,
|
|
|
|
description: 'Failed to get user information.',
|
|
|
|
placement: 'top',
|
|
|
|
duration: 4,
|
|
|
|
});
|
|
|
|
});
|
|
|
|
})
|
|
|
|
.catch(ex => {
|
|
|
|
notification.error({
|
|
|
|
message: `Notification`,
|
|
|
|
description: ex.message,
|
|
|
|
placement: 'top',
|
|
|
|
duration: 4,
|
|
|
|
});
|
|
|
|
});
|
|
|
|
setPassword('');
|
|
|
|
};
|
|
|
|
|
|
|
|
const splitPath = href.split("/");
|
|
|
|
let defaultPath = "reservation";
|
|
|
|
|
|
|
|
if (splitPath.length > 1) {
|
|
|
|
defaultPath = splitPath[1];
|
|
|
|
}
|
|
|
|
|
|
|
|
const {
|
|
|
|
token: { colorBgContainer },
|
|
|
|
} = theme.useToken();
|
|
|
|
|
|
|
|
const [antdLng, setAntdLng] = useState(enLocale);
|
|
|
|
useEffect(() => {
|
|
|
|
setAntdLng(i18n.language === 'en' ? enLocale : zhLocale);
|
|
|
|
}, [i18n.language]);
|
|
|
|
return (
|
|
|
|
<ConfigProvider locale={antdLng}
|
|
|
|
theme={{
|
|
|
|
token: {
|
|
|
|
colorPrimary: "#00b96b",
|
|
|
|
},
|
|
|
|
algorithm: theme.defaultAlgorithm,
|
|
|
|
}}>
|
|
|
|
<AntApp>
|
|
|
|
<Modal
|
|
|
|
centered
|
|
|
|
closable={false}
|
|
|
|
maskClosable={false}
|
|
|
|
footer={null}
|
|
|
|
open={login.timeout}
|
|
|
|
>
|
|
|
|
<Title level={3}>{t('LoginTimeout')}</Title>
|
|
|
|
<div>{t('LoginTimeoutTip')}</div>
|
|
|
|
<Space direction="horizontal">
|
|
|
|
<Input.Password value={password}
|
|
|
|
onChange={(e) => setPassword(e.target.value)}
|
|
|
|
onPressEnter={() => onSubmit()}
|
|
|
|
addonBefore={login.username} />
|
|
|
|
<Button
|
|
|
|
onClick={() => onSubmit()}
|
|
|
|
>{t('Submit')}</Button></Space>
|
|
|
|
|
|
|
|
</Modal>
|
|
|
|
<Layout
|
|
|
|
style={{
|
|
|
|
minHeight: "100vh",
|
|
|
|
}}>
|
|
|
|
<Header className="header" style={{ position: "sticky", top: 0, zIndex: 1, width: "100%" }}>
|
|
|
|
<Row gutter={{ md: 24 }} justify="end" align="middle">
|
|
|
|
<Col span={16}>
|
|
|
|
<NavLink to="/">
|
|
|
|
<img src={AppLogo} className="logo" alt="App logo" />
|
|
|
|
</NavLink>
|
|
|
|
<Menu
|
|
|
|
theme="dark"
|
|
|
|
mode="horizontal"
|
|
|
|
selectedKeys={[defaultPath]}
|
|
|
|
items={[
|
|
|
|
{ key: "reservation", label: <Link to="/reservation/newest">{t('menu.Reservation')}</Link> },
|
|
|
|
{ key: "invoice", label: <Link to="/invoice">{t('menu.Invoice')}</Link> },
|
|
|
|
{ key: "feedback", label: <Link to="/feedback">{t('menu.Feedback')}</Link> },
|
|
|
|
// { key: "report", label: <Link to="/report">Report</Link> },
|
|
|
|
{
|
|
|
|
key: "notice",
|
|
|
|
label: (
|
|
|
|
<Link to="/notice">
|
|
|
|
{t('menu.Notice')}
|
|
|
|
{noticeUnRead ? <Badge dot /> : ""}
|
|
|
|
</Link>
|
|
|
|
),
|
|
|
|
},
|
|
|
|
]}
|
|
|
|
/>
|
|
|
|
</Col>
|
|
|
|
<Col span={4}>
|
|
|
|
<Title level={3} style={{ color: "white", marginBottom: "0", display: "flex", justifyContent: "end" }}>
|
|
|
|
{authStore.login.travelAgencyName}
|
|
|
|
</Title>
|
|
|
|
</Col>
|
|
|
|
<Col span={2}>
|
|
|
|
<Dropdown
|
|
|
|
menu={{
|
|
|
|
items: [...items,
|
|
|
|
{ type: 'divider' },
|
|
|
|
{ label: <>v{BUILD_VERSION}</>, key: 'BUILD_VERSION' },
|
|
|
|
],
|
|
|
|
}}
|
|
|
|
trigger={['click']}
|
|
|
|
>
|
|
|
|
<a onClick={e => e.preventDefault()}>
|
|
|
|
<Space>
|
|
|
|
{authStore.login.username}
|
|
|
|
<DownOutlined />
|
|
|
|
</Space>
|
|
|
|
</a>
|
|
|
|
</Dropdown>
|
|
|
|
</Col>
|
|
|
|
<Col span={2}>
|
|
|
|
<Language />
|
|
|
|
</Col>
|
|
|
|
</Row>
|
|
|
|
</Header>
|
|
|
|
<Content
|
|
|
|
style={{
|
|
|
|
padding: 24,
|
|
|
|
margin: 0,
|
|
|
|
minHeight: 280,
|
|
|
|
background: colorBgContainer,
|
|
|
|
}}>
|
|
|
|
<Outlet />
|
|
|
|
</Content>
|
|
|
|
<Footer></Footer>
|
|
|
|
</Layout>
|
|
|
|
</AntApp>
|
|
|
|
</ConfigProvider>
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
export default observer(App);
|