-
-
-
Ant Design Pro
-
+
+
+
+
+
+
+
Ant Design Pro
+
+
+
+
+
+
-
-
-
-
);
diff --git a/src/components/TopNavHeader/index.less b/src/components/TopNavHeader/index.less
index 037b12b0f7bb04a030166de0dcb9791e14dd1db7..456fc548af586a33c4e97fdee558249ad64aba5b 100644
--- a/src/components/TopNavHeader/index.less
+++ b/src/components/TopNavHeader/index.less
@@ -1,31 +1,53 @@
-.main {
- display: flex;
+.head {
+ width: 100%;
+ transition: background 0.3s, width 0.2s;
height: 64px;
- margin: auto;
- max-width: 1200px;
- .left {
- flex: 1;
+ padding: 0 12px 0 0;
+ box-shadow: 0 1px 4px rgba(0, 21, 41, 0.08);
+ position: relative;
+ &.ligth {
+ background-color: #fff;
+ }
+ .main {
display: flex;
- .logo {
- width: 160px;
- height: 64px;
- position: relative;
- line-height: 64px;
- transition: all 0.3s;
- overflow: hidden;
- img {
- display: inline-block;
- vertical-align: middle;
- height: 32px;
- }
- h1 {
- color: #fff;
- display: inline-block;
- vertical-align: middle;
- font-size: 16px;
- margin: 0 0 0 12px;
- font-weight: 400;
- }
+ height: 64px;
+ padding-left: 24px;
+ &.wide {
+ max-width: 1200px;
+ margin: auto;
+ padding-left: 4px;
+ }
+ .left {
+ flex: 1;
+ display: flex;
}
}
}
+
+.logo {
+ width: 160px;
+ height: 64px;
+ position: relative;
+ line-height: 64px;
+ transition: all 0.3s;
+ overflow: hidden;
+ img {
+ display: inline-block;
+ vertical-align: middle;
+ height: 32px;
+ }
+ h1 {
+ color: #fff;
+ display: inline-block;
+ vertical-align: middle;
+ font-size: 16px;
+ margin: 0 0 0 12px;
+ font-weight: 400;
+ }
+}
+
+.ligth {
+ h1 {
+ color: #002140;
+ }
+}
diff --git a/src/index.less b/src/index.less
index 5cfe914a4cec038c252fa4f0069e50b11b8cc6cc..d8b1560fcea1d25f534ee86f7c120f34bef4f470 100644
--- a/src/index.less
+++ b/src/index.less
@@ -2,6 +2,7 @@ html,
body,
:global(#root) {
height: 100%;
+ overflow: auto;
}
:global(.ant-layout) {
diff --git a/src/layouts/BasicLayout.js b/src/layouts/BasicLayout.js
index f6237e8e854674c07817be711034258999a396aa..8ef41f6105d098ee4158bb40caa1dc347509e5b5 100644
--- a/src/layouts/BasicLayout.js
+++ b/src/layouts/BasicLayout.js
@@ -1,43 +1,24 @@
-import React, { Fragment } from 'react';
+import React from 'react';
import PropTypes from 'prop-types';
-import { Layout, Icon, message } from 'antd';
+import { Layout } from 'antd';
import DocumentTitle from 'react-document-title';
import { connect } from 'dva';
-import { Route, Redirect, Switch, routerRedux } from 'dva/router';
+import { Route, Redirect, Switch } from 'dva/router';
import { ContainerQuery } from 'react-container-query';
import classNames from 'classnames';
-import { enquireScreen } from 'enquire-js';
-import GlobalHeader from '../components/GlobalHeader';
-import GlobalFooter from '../components/GlobalFooter';
-import TopNavHeader from '../components/TopNavHeader';
import SiderMenu from '../components/SiderMenu';
import NotFound from '../routes/Exception/404';
import { getRoutes } from '../utils/utils';
import Authorized from '../utils/Authorized';
-import { getMenuData } from '../common/menu';
+import Sidebar from '../components/Sidebar';
import logo from '../assets/logo.svg';
+import Footer from './Footer';
+import Header from './Header';
-const { Content, Header, Footer } = Layout;
+const { Content } = Layout;
const { AuthorizedRoute } = Authorized;
-/**
- * 根据菜单取得重定向地址.
- */
-const redirectData = [];
-const getRedirect = (item) => {
- if (item && item.children) {
- if (item.children[0] && item.children[0].path) {
- redirectData.push({
- from: `${item.path}`,
- to: `${item.children[0].path}`,
- });
- item.children.forEach((children) => {
- getRedirect(children);
- });
- }
- }
-};
-getMenuData().forEach(getRedirect);
+const RightSidebar = connect(({ setting }) => ({ ...setting }))(Sidebar);
const query = {
'screen-xs': {
@@ -59,19 +40,10 @@ const query = {
minWidth: 1200,
},
};
-
-let isMobile;
-enquireScreen((b) => {
- isMobile = b;
-});
-
class BasicLayout extends React.PureComponent {
static childContextTypes = {
location: PropTypes.object,
breadcrumbNameMap: PropTypes.object,
- }
- state = {
- isMobile,
};
getChildContext() {
const { location, routerData } = this.props;
@@ -80,16 +52,6 @@ class BasicLayout extends React.PureComponent {
breadcrumbNameMap: routerData,
};
}
- componentDidMount() {
- enquireScreen((mobile) => {
- this.setState({
- isMobile: mobile,
- });
- });
- this.props.dispatch({
- type: 'user/fetchCurrent',
- });
- }
getPageTitle() {
const { routerData, location } = this.props;
const { pathname } = location;
@@ -113,150 +75,73 @@ class BasicLayout extends React.PureComponent {
return '/dashboard/analysis';
}
return redirect;
- }
+ };
handleMenuCollapse = (collapsed) => {
this.props.dispatch({
type: 'global/changeLayoutCollapsed',
payload: collapsed,
});
- }
- handleNoticeClear = (type) => {
- message.success(`清空了${type}`);
+ };
+ changeSetting = (setting) => {
this.props.dispatch({
- type: 'global/clearNotices',
- payload: type,
+ type: 'setting/changeSetting',
+ payload: setting,
});
}
- handleMenuClick = ({ key }) => {
- if (key === 'userCenter') {
- this.props.dispatch(routerRedux.push('/user-profile/user-center'));
- return;
- }
- if (key === 'triggerError') {
- this.props.dispatch(routerRedux.push('/exception/trigger'));
- return;
- }
- if (key === 'userinfo') {
- this.props.dispatch(routerRedux.push('/user-profile/userinfo/base'));
- return;
- }
- if (key === 'logout') {
- this.props.dispatch({
- type: 'login/logout',
- });
- }
- }
- handleNoticeVisibleChange = (visible) => {
- if (visible) {
- this.props.dispatch({
- type: 'global/fetchNotices',
- });
- }
- }
render() {
- const isFluid = this.props.layout === 'fluid';
const {
- currentUser, collapsed, fetchingNotices, notices, routerData, match, location,
+ isMobile,
+ redirectData,
+ routerData,
+ fixedHeader,
+ match,
} = this.props;
+ const isTop = this.props.layout === 'topmenu';
const bashRedirect = this.getBashRedirect();
+ const myRedirectData = redirectData || [];
const layout = (
- {isFluid && !isMobile ? null : (
+ {isTop && !isMobile ? null : (
)}
-
- {isFluid && !isMobile ? (
-
- ) : (
-
- )}
-
-
+
+
- {
- redirectData.map(item =>
-
- )
- }
- {
- getRoutes(match.path, routerData).map(item =>
- (
-
- )
- )
- }
+ {myRedirectData.map(item => (
+
+ ))}
+ {getRoutes(match.path, routerData).map(item => (
+
+ ))}
-
+
);
@@ -264,17 +149,20 @@ class BasicLayout extends React.PureComponent {
return (
- {params => {layout}
}
+ {params => (
+
+ {layout}
+
+
+ )}
);
}
}
-export default connect(({ user, global, loading }) => ({
- currentUser: user.currentUser,
+export default connect(({ global, setting }) => ({
collapsed: global.collapsed,
- layout: global.layout,
- fetchingNotices: loading.effects['global/fetchNotices'],
- notices: global.notices,
+ layout: setting.layout,
+ ...setting,
}))(BasicLayout);
diff --git a/src/layouts/Footer.js b/src/layouts/Footer.js
new file mode 100644
index 0000000000000000000000000000000000000000..902d4ab881fa1526d59375357475774cac5e991c
--- /dev/null
+++ b/src/layouts/Footer.js
@@ -0,0 +1,38 @@
+
+import React, { Fragment } from 'react';
+import { Layout, Icon } from 'antd';
+import GlobalFooter from '../components/GlobalFooter';
+
+const { Footer } = Layout;
+const FooterView = () => (
+
+);
+export default FooterView;
diff --git a/src/layouts/GridContent.js b/src/layouts/GridContent.js
index 60c22d5d24fc43917ebb3824f345a1642fa71a58..09af81397cd53883dd0456452d2d942c93cd69fa 100644
--- a/src/layouts/GridContent.js
+++ b/src/layouts/GridContent.js
@@ -5,13 +5,13 @@ import styles from './GridContent.less';
class GridContent extends PureComponent {
render() {
let className = `${styles.main}`;
- if (this.props.layout === 'fluid') {
- className = `${styles.main} ${styles.fluid}`;
+ if (this.props.grid === 'Wide') {
+ className = `${styles.main} ${styles.wide}`;
}
return
{this.props.children}
;
}
}
-export default connect(({ global }) => ({
- layout: global.layout,
+export default connect(({ setting }) => ({
+ grid: setting.grid,
}))(GridContent);
diff --git a/src/layouts/GridContent.less b/src/layouts/GridContent.less
index b06ad0c6e28ba8819d35f0c326f2aad15427189b..d5496e9ecb95318c38a30f1369d35e8fcf583758 100644
--- a/src/layouts/GridContent.less
+++ b/src/layouts/GridContent.less
@@ -2,7 +2,8 @@
width: 100%;
height: 100%;
min-height: 100%;
- &.fluid {
+ transition: 0.3s;
+ &.wide {
max-width: 1200px;
margin: 0 auto;
}
diff --git a/src/layouts/Header.js b/src/layouts/Header.js
new file mode 100644
index 0000000000000000000000000000000000000000..52def2d573db311695fe53d640d287951907a707
--- /dev/null
+++ b/src/layouts/Header.js
@@ -0,0 +1,153 @@
+import React, { PureComponent } from 'react';
+import { Layout, message } from 'antd';
+import Animate from 'rc-animate';
+import { connect } from 'dva';
+import { routerRedux } from 'dva/router';
+import GlobalHeader from '../components/GlobalHeader';
+import TopNavHeader from '../components/TopNavHeader';
+import styles from './Header.less';
+import Authorized from '../utils/Authorized';
+
+const { Header } = Layout;
+
+class HeaderView extends PureComponent {
+ state = {
+ visible: true,
+ };
+ componentDidMount() {
+ document.getElementById('root').addEventListener('scroll', this.handScroll);
+ }
+ componentWillUnmount() {
+ document
+ .getElementById('root')
+ .removeEventListener('scroll', this.handScroll);
+ }
+ getHeadWidth = () => {
+ if (
+ !this.props.fixedHeader ||
+ this.props.layout === 'topmenu' ||
+ this.props.fixSiderbar
+ ) {
+ return '100%';
+ }
+ if (!this.props.collapsed) {
+ return 'calc(100% - 256px)';
+ }
+ if (this.props.collapsed) {
+ return 'calc(100% - 80px)';
+ }
+ };
+ handleNoticeClear = (type) => {
+ message.success(`清空了${type}`);
+ this.props.dispatch({
+ type: 'global/clearNotices',
+ payload: type,
+ });
+ };
+ handleMenuClick = ({ key }) => {
+ if (key === 'userCenter') {
+ this.props.dispatch(routerRedux.push('/user-profile/user-center'));
+ return;
+ }
+ if (key === 'triggerError') {
+ this.props.dispatch(routerRedux.push('/exception/trigger'));
+ return;
+ }
+ if (key === 'userinfo') {
+ this.props.dispatch(routerRedux.push('/user-profile/userinfo/base'));
+ return;
+ }
+ if (key === 'logout') {
+ this.props.dispatch({
+ type: 'login/logout',
+ });
+ }
+ };
+ handleNoticeVisibleChange = (visible) => {
+ if (visible) {
+ this.props.dispatch({
+ type: 'global/fetchNotices',
+ });
+ }
+ };
+ handScroll = () => {
+ if (!this.props.autoHideHeader) {
+ return;
+ }
+ const { scrollTop } = document.getElementById('root');
+ if (!this.ticking) {
+ this.ticking = false;
+ requestAnimationFrame(() => {
+ if (scrollTop > 400 && this.state.visible) {
+ this.setState({
+ visible: false,
+ });
+ }
+ if (scrollTop < 400 && !this.state.visible) {
+ this.setState({
+ visible: true,
+ });
+ }
+ this.ticking = false;
+ });
+ }
+ };
+ render() {
+ const {
+ logo,
+ isMobile,
+ handleMenuCollapse,
+ silderTheme,
+ layout,
+ fixedHeader,
+ } = this.props;
+ const isTop = layout === 'topmenu';
+ const HeaderDom = this.state.visible ? (
+
+ {isTop && !isMobile ? (
+
+ ) : (
+
+ )}
+
+ ) : null;
+ return (
+
+ {HeaderDom}
+
+ );
+ }
+}
+
+export default connect(({ user, global, setting, loading }) => ({
+ currentUser: user.currentUser,
+ collapsed: global.collapsed,
+ fetchingNotices: loading.effects['global/fetchNotices'],
+ notices: global.notices,
+ layout: setting.layout,
+ silderTheme: setting.silderTheme,
+ fixedHeader: setting.fixedHeader,
+ fixSiderbar: setting.fixSiderbar,
+ autoHideHeader: setting.autoHideHeader,
+}))(HeaderView);
diff --git a/src/layouts/Header.less b/src/layouts/Header.less
new file mode 100644
index 0000000000000000000000000000000000000000..3bd5b52309e086920a5976783541b9eedf09192d
--- /dev/null
+++ b/src/layouts/Header.less
@@ -0,0 +1,6 @@
+.fixedHeader {
+ position: fixed;
+ top: 0;
+ width: 100%;
+ z-index: 9;
+}
diff --git a/src/layouts/LoadingPage.js b/src/layouts/LoadingPage.js
new file mode 100644
index 0000000000000000000000000000000000000000..3ce2ac7da9a3b324e68447e7671cde5017720cfd
--- /dev/null
+++ b/src/layouts/LoadingPage.js
@@ -0,0 +1,94 @@
+import React, { PureComponent } from 'react';
+import { Spin } from 'antd';
+import { enquireScreen } from 'enquire-js';
+import { connect } from 'dva';
+import BasicLayout from './BasicLayout';
+import { getMenuData } from '../common/menu';
+
+/**
+ * 根据菜单取得重定向地址.
+ */
+
+const MenuData = getMenuData();
+const getRedirectData = () => {
+ const redirectData = [];
+ const getRedirect = (item) => {
+ if (item && item.children) {
+ if (item.children[0] && item.children[0].path) {
+ redirectData.push({
+ from: `${item.path}`,
+ to: `${item.children[0].path}`,
+ });
+ item.children.forEach((children) => {
+ getRedirect(children);
+ });
+ }
+ }
+ };
+ MenuData.forEach(getRedirect);
+ return redirectData;
+};
+const redirectData = getRedirectData();
+
+class LodingPage extends PureComponent {
+ state = {
+ loading: true,
+ isMobile: false,
+ };
+ componentDidMount() {
+ enquireScreen((mobile) => {
+ this.setState({
+ isMobile: mobile,
+ });
+ });
+ this.props.dispatch({
+ type: 'user/fetchCurrent',
+ });
+ const urlParams = new URL(window.location.href);
+ const settingString = urlParams.searchParams.get('setting');
+ if (settingString) {
+ const setting = {};
+ settingString.split(';').forEach((keyValue) => {
+ const [key, value] = keyValue.split(':');
+ setting[key] = value;
+ });
+ this.props.dispatch({
+ type: 'setting/changeSetting',
+ payload: setting,
+ });
+ }
+ this.hideLoading();
+ }
+ hideLoading() {
+ this.setState({
+ loading: false,
+ });
+ }
+ render() {
+ if (this.state.loading) {
+ return (
+
+
+
+ );
+ }
+ return (
+
+ );
+ }
+}
+
+export default connect()(LodingPage);
diff --git a/src/models/global.js b/src/models/global.js
index 64221aaad55adbb09f0ea73ec6ede75efe4b6c06..55841e16d053db3bf4c92b94ce877cd6601d4965 100644
--- a/src/models/global.js
+++ b/src/models/global.js
@@ -5,7 +5,6 @@ export default {
state: {
collapsed: false,
- layout: 'fluid',
notices: [],
},
@@ -41,12 +40,6 @@ export default {
collapsed: payload,
};
},
- changeLayout(state, { payload }) {
- return {
- ...state,
- layout: payload,
- };
- },
saveNotices(state, { payload }) {
return {
...state,
diff --git a/src/models/setting.js b/src/models/setting.js
new file mode 100644
index 0000000000000000000000000000000000000000..e2a554e6c725ab1ccbfb1565f9c4a738f506b416
--- /dev/null
+++ b/src/models/setting.js
@@ -0,0 +1,32 @@
+export default {
+ namespace: 'setting',
+
+ state: {
+ collapse: false,
+ silderTheme: 'dark',
+ themeColor: '#1890FF',
+ layout: 'sidemenu',
+ grid: 'Fluid',
+ fixedHeader: false,
+ autoHideHeader: false,
+ fixSiderbar: false,
+ colorWeak: 'close',
+ },
+ reducers: {
+ changeSetting(state, { payload }) {
+ const urlParams = new URL(window.location.href);
+ let urlParamsString = '';
+ Object.keys(payload).forEach((key) => {
+ if (payload[key] && state[key] !== undefined && key !== 'collapse') {
+ urlParamsString += `${key}:${payload[key]};`;
+ }
+ });
+ urlParams.searchParams.set('setting', urlParamsString);
+ window.history.replaceState(null, 'setting', urlParams.href);
+ return {
+ ...state,
+ ...payload,
+ };
+ },
+ },
+};
diff --git a/src/routes/UserProfile/UserCenter.js b/src/routes/UserProfile/UserCenter.js
index a1a603d3391e21e09cc209e0c110f7aa83f02516..ada929cbde311a62ccf11fb628a8d3fd8f58ff2c 100644
--- a/src/routes/UserProfile/UserCenter.js
+++ b/src/routes/UserProfile/UserCenter.js
@@ -22,9 +22,9 @@ import AvatarList from '../../components/AvatarList';
import { formatWan } from '../../utils/utils';
import styles from './UserCenter.less';
import stylesProjects from '../List/Projects.less';
-import stylesArticles from './List/Articles.less';
-import stylesApplications from './List/Applications.less';
-import GridContent from '../layouts/GridContent';
+import stylesArticles from '../List/Articles.less';
+import stylesApplications from '../List/Applications.less';
+import GridContent from '../../layouts/GridContent';
@connect(({ list, loading, user, project }) => ({
list,
diff --git a/src/routes/UserProfile/Userinfo/Info.js b/src/routes/UserProfile/Userinfo/Info.js
index 4281fcb213dc2ecea0ea1d23f89126b7ef97ec7e..57b07d8c5d487c4bfae80197d0d0fb2439090a40 100644
--- a/src/routes/UserProfile/Userinfo/Info.js
+++ b/src/routes/UserProfile/Userinfo/Info.js
@@ -3,8 +3,8 @@ import { connect } from 'dva';
import { Route, routerRedux, Switch, Redirect } from 'dva/router';
import { Menu } from 'antd';
import styles from './Info.less';
-import { getRoutes } from '../../utils/utils';
-import GridContent from '../../layouts/GridContent';
+import { getRoutes } from '../../../utils/utils';
+import GridContent from '../../../layouts/GridContent';
const { Item } = Menu;