Auth.jsjavascript
import {session, stoage} from './util' const NotLoginAuth = [ '/login', '/register', '/register/complete', '/register/fail', '/forgetpassword' ] /** * 分角色控制權限和菜單 */ const RoleAssentPath = { GUEST : [ ...NotLoginAuth, ], USER : [ ...NotLoginAuth, '/', '/user', ], COMPANY : [ ...NotLoginAuth, '/', '/company', '/user', '/user/list', '/user/add', '/user/edit', ], ADMIN : [ ...NotLoginAuth, '/', '/channel', '/channel/add', '/channel/list', '/company', '/company/add', '/company/list', '/company/edit', ], } export const getRoute = () => { return RoleAssentPath[LoginInfo.role] } let LoginInfo = { logined : false, username : null, role : 'GUEST', // ADMIN | COMPANY | USER | GUEST } export const Login = (userInfo, remember) =>{ LoginInfo = { ...userInfo, logined : true, lastime : new Date().getTime(), } if(remember){ stoage.setStore('UserInfo', LoginInfo) } session.setStore('UserInfo', LoginInfo) } export const LoginOut = () =>{ LoginInfo = { logined : false, role : 'GUEST', } session.removeStore('UserInfo') stoage.removeStore('UserInfo') } export const getUser = () =>{ if(LoginInfo.logined === false){ let storeUser = stoage.getStore('UserInfo') if(storeUser && storeUser.logined){ Login(storeUser) } } return LoginInfo } export default (nextState, replace) => { let path = nextState.location.pathname.toLocaleLowerCase() if(path == '/loginout'){ LoginOut() replace('/login') }else if(NotLoginAuth.indexOf(path) == -1 && getUser().logined == false){ replace('/login') }else if(getRoute().indexOf(path)==-1){ console.log('沒有權限') replace('/error/401') } }
route.jscss
/** * 定義應用路由 */ import React from 'react'; import { Router, hashHistory, } from 'react-router'; import auth from './auth'; // 路由配置規則參考: https://github.com/ReactTraining/react-router/blob/v3/docs/guides/RouteConfiguration.md#configuration-with-plain-routes // 一下部分是由 ICE 相關工具自動生成的路由,請勿隨意改變,不然可能會出現一些異常狀況 // <!-- auto generated routes start --> import ForgetPassword from "./pages/ForgetPassword"; import Login from "./pages/Login"; import HeaderAsideFooterResponsiveLayout from './layouts/HeaderAsideFooterResponsiveLayout'; import BlankLayout from './layouts/BlankLayout'; import Home from './pages/Home'; import HeaderFooterLayout from './layouts/HeaderFooterLayout'; import { NotFound, BasicException, NotPermission, EmptyContent } from './pages/ErrorPage'; import { Register, RegisterComplete, RegisterFail } from "./pages/Register"; import { Channel, AddChannel, EditChannel } from "./pages/Channel"; import { Company, AddCompany, EditCompany } from "./pages/Company"; import { User, AddUser } from "./pages/User"; const autoGeneratedRoutes = [{ path: "/company", childRoutes: [{ path: "list", component: Company, onEnter: auth }, { path: "add", component: AddCompany, onEnter: auth }, { path: "edit/:id", component: EditCompany, onEnter: auth }], component: HeaderAsideFooterResponsiveLayout, onEnter: auth }, { path: "/channel", childRoutes: [{ path: "list", component: Channel, onEnter: auth }, { path: "add", component: AddChannel, onEnter: auth }, { path: "edit/:id", component: EditChannel, onEnter: auth }], component: HeaderAsideFooterResponsiveLayout, onEnter: auth }, { path: "/user", childRoutes: [{ path: "list", component: User, onEnter: auth }, { path: "add", component: AddUser, onEnter: auth }], component: HeaderAsideFooterResponsiveLayout, onEnter: auth }, { path: "/error", childRoutes: [{ path: "401", component: NotPermission }, { path: "404", component: NotFound }, { path: "500", component: BasicException }, { path: "empty", component: EmptyContent }], component: BlankLayout, indexRoute: { component: NotFound } }, { path: "/forgetPassword", childRoutes: [], component: BlankLayout, indexRoute: { component: ForgetPassword }, onEnter: auth }, { path: "/register", childRoutes: [ { path: "complete", component: RegisterComplete }, { path: "fail", component: RegisterFail } ], component: BlankLayout, indexRoute: { component: Register }, onEnter: auth }, { path: "/login", childRoutes: [], component: BlankLayout, indexRoute: { component: Login }, onEnter: auth }, { path: "/loginout", childRoutes: [], component: BlankLayout, indexRoute: { component: Login }, onEnter: auth }, { path: '/', childRoutes: [{ path: '*', childRoutes: [], component: NotFound }], component: HeaderAsideFooterResponsiveLayout, indexRoute: { component: Home }, onEnter: auth }]; // <!-- auto generated routes end --> // 自定義路由,若是 path 相同則會覆蓋自動生成部分的路由配置 const customRoutes = []; export default ( <Router history={hashHistory} routes={[...autoGeneratedRoutes, ...customRoutes]} /> );
HeaderAsideFooterResponsiveLayout/Layout.jsjava
/* eslint no-undef:0, no-unused-expressions:0, array-callback-return:0 */ import React, { Component } from 'react'; import cx from 'classnames'; import Layout from '@icedesign/layout'; import { Icon } from '@icedesign/base'; import Menu, { SubMenu, Item as MenuItem } from '@icedesign/menu'; import { Link } from 'react-router'; import FoundationSymbol from 'foundation-symbol'; import { enquire } from 'enquire-js'; import Header from './../../components/Header'; import Footer from './../../components/Footer'; import Logo from './../../components/Logo'; import { asideNavs } from './../../navs'; import './scss/light.scss'; import './scss/dark.scss'; import { getRoute } from '../../auth' // 設置默認的皮膚配置,支持 dark 和 light 兩套皮膚配置 const theme = typeof THEME === 'undefined' ? 'light' : THEME; export default class HeaderAsideFooterResponsiveLayout extends Component { static propTypes = {}; static defaultProps = {}; constructor(props) { super(props); const openKeys = this.getOpenKeys(); this.state = { collapse: false, openDrawer: false, isScreen: undefined, openKeys, }; this.openKeysCache = openKeys; } getAsideNavs = () =>{ if(this.asideNavs == null){ let routes = getRoute() let allMenu = asideNavs.filter(m=> routes.indexOf(m.to) != -1 ) allMenu.forEach(m=>{ if(m.children){ m.children = m.children.filter(m=> routes.indexOf(m.to) != -1) } }) this.asideNavs = allMenu } return this.asideNavs } componentDidMount() { this.enquireScreenRegister(); } /** * 註冊監聽屏幕的變化,可根據不一樣分辨率作對應的處理 */ enquireScreenRegister = () => { const isMobile = 'screen and (max-width: 720px)'; const isTablet = 'screen and (min-width: 721px) and (max-width: 1199px)'; const isDesktop = 'screen and (min-width: 1200px)'; enquire.register(isMobile, this.enquireScreenHandle('isMobile')); enquire.register(isTablet, this.enquireScreenHandle('isTablet')); enquire.register(isDesktop, this.enquireScreenHandle('isDesktop')); }; enquireScreenHandle = (type) => { let collapse; if (type === 'isMobile') { collapse = false; } else if (type === 'isTablet') { collapse = true; } else { collapse = this.state.collapse; } const handler = { match: () => { this.setState({ isScreen: type, collapse, }); }, unmatch: () => { // handler unmatched }, }; return handler; }; /** * 左側菜單收縮切換 */ toggleCollapse = () => { const { collapse } = this.state; const openKeys = !collapse ? [] : this.openKeysCache; this.setState({ collapse: !collapse, openKeys, }); }; /** * 響應式經過抽屜形式切換菜單 */ toggleMenu = () => { const { openDrawer } = this.state; this.setState({ openDrawer: !openDrawer, }); }; /** * 當前展開的菜單項 */ onOpenChange = (openKeys) => { this.setState({ openKeys, }); this.openKeysCache = openKeys; }; /** * 響應式時點擊菜單進行切換 */ onMenuClick = () => { this.toggleMenu(); }; /** * 獲取當前展開的菜單項 */ getOpenKeys = () => { const { routes } = this.props; const matched = routes[0].path; const asideNavs = this.getAsideNavs() let openKeys = []; asideNavs && asideNavs.length > 0 && asideNavs.map((item, index) => { if (item.to === matched) { openKeys = [`${index}`]; } }); return openKeys; }; render() { const { location = {} } = this.props; const { pathname } = location; const asideNavs = this.getAsideNavs() return ( <Layout style={{ minHeight: '100vh' }} className={cx( `ice-design-header-aside-footer-responsive-layout-${theme}`, { 'ice-design-layout': true, } )} > <Header theme={theme} isMobile={this.state.isScreen !== 'isDesktop' ? true : undefined} /> <Layout.Section> {this.state.isScreen === 'isMobile' && ( <a className="menu-btn" onClick={this.toggleMenu}> <Icon type="category" size="small" /> </a> )} {this.state.openDrawer && ( <div className="open-drawer-bg" onClick={this.toggleMenu} /> )} <Layout.Aside width="auto" theme={theme} className={cx('ice-design-layout-aside', { 'open-drawer': this.state.openDrawer, })} > {/* 側邊菜單項 begin */} {this.state.isScreen !== 'isMobile' && ( <a className="collapse-btn" onClick={this.toggleCollapse}> <Icon type={this.state.collapse ? 'arrow-right' : 'arrow-left'} size="small" /> </a> )} {this.state.isScreen === 'isMobile' && <Logo />} <Menu style={{ width: this.state.collapse ? 60 : 200 }} inlineCollapsed={this.state.collapse} mode="inline" selectedKeys={[pathname]} openKeys={this.state.openKeys} defaultSelectedKeys={[pathname]} onOpenChange={this.onOpenChange} onClick={this.onMenuClick} > {asideNavs && asideNavs.length > 0 && asideNavs.map((nav, index) => { if (nav.children && nav.children.length > 0) { return ( <SubMenu key={index} title={ <span> {nav.icon ? ( <FoundationSymbol size="small" type={nav.icon} /> ) : null} <span className="ice-menu-collapse-hide"> {nav.text} </span> </span> } > {nav.children.map((item) => { const linkProps = {}; if (item.newWindow) { linkProps.href = item.to; linkProps.target = '_blank'; } else if (item.external) { linkProps.href = item.to; } else { linkProps.to = item.to; } return ( <MenuItem key={item.to}> <Link {...linkProps}>{item.text}</Link> </MenuItem> ); })} </SubMenu> ); } const linkProps = {}; if (nav.newWindow) { linkProps.href = nav.to; linkProps.target = '_blank'; } else if (nav.external) { linkProps.href = nav.to; } else { linkProps.to = nav.to; } return ( <MenuItem key={nav.to}> <Link {...linkProps}> <span> {nav.icon ? ( <FoundationSymbol size="small" type={nav.icon} /> ) : null} <span className="ice-menu-collapse-hide"> {nav.text} </span> </span> </Link> </MenuItem> ); })} </Menu> {/* 側邊菜單項 end */} </Layout.Aside> {/* 主體內容 */} <Layout.Main>{this.props.children}</Layout.Main> </Layout.Section> <Footer /> </Layout> ); } }