Umi: 关于菜单权限的问题(动态菜单)

Created on 4 Sep 2018  ·  4Comments  ·  Source: umijs/umi

环境:umi@2 + dva + antd
我在使用Menu时遇到点问题,使用嵌套路由

  • pages/

    • users/

    • _layout.js ->连接model 监听/users

    • child.js -> 连接model 监听/users/child

    • index.js

在_layout.js使用了menu,并且连接了model去获取menu数据,访问/users时能正常展现出菜单的,点击菜单访问/users/child时也是能正常展现菜单的,但是刷新/users/child后菜单数据就没了,调试了下,发现_layout.js重新加载,并且由于地址并不是监听的/users,所以没有去获取菜单数据
我有两个问题希望有大神能指点下:
1.subscriptions监听嵌套地址时,不能先监听到/users,执行完相应的方法之后再执行监听/users/child么?
2.动态菜单加载作为大多数后端管理系统会使用到的内容,我看了antd-pro是所有菜单项写死menu.js里,但是每个用户能看到的菜单项如果要求不同的话该怎么处理?现在手头项目是登录之后获取能看到的菜单,然后保存到sessionStorage中,然后加载_layout.js时从sessionStorage里去获取,这样是不是合理?或者有更加合适的处理方式?

Most helpful comment

菜单权限,你可以写全局model啊,
我的类似这种:

import {getProfile, logout} from '~services/global';

export default {
  namespace: 'global',
  state: {
    user: {}
  },
  reducers: {
    changeUserInfo(state, {payload}) {
      state.user = payload.user;
      return state;
    }
  },
  effects: {
    * getProfile(actions, {call, put}) {
      try {
        const res = yield call(getProfile);
        yield put({type: 'changeUserInfo', payload: {user: res.profile}})
      } catch (e) {
        window.location.href = '/login';
      }
    },

    * logout(actions, {call, put}) {
      let res = yield call(logout);
      console.log(res);
      window.location.href = '/login'
    }

  },
  subscriptions: {
    setup({dispatch, history}) {
      const {location: {pathname}} = history;
      if (pathname !== '/login') {
        dispatch({type: 'getProfile'})
      }
    }
  },

}

这里的user即当前登录者,包含从api获取的信息(例如:name, account, permission, isAdmin, isMaster, ...)

然后在layout就可以获取到权限了呀
layout/index.js:

import {Layout} from 'antd';

import {connect} from 'dva';
import React from 'react';
import styles from './index.less';
import Header from './Header';
import Footer from './Footer';
import Sider from './Sider';
import withRouter from 'umi/withRouter';
import Loading from '~components/Loading';

const {Content} = Layout;

const mapState2props = ({global, loading}) => {
  return {
    global,
    loading,
    menus: global.user.permission
  }
};

@withRouter
@connect(mapState2props)
export default class NdLayout extends React.PureComponent {
  state = {
    collapsed: false
  };
  toggle = () => {
    this.setState({
      collapsed: !this.state.collapsed
    })
  };
  onHeaderMenuClick = ({key}) => {
    const {dispatch} = this.props;
    if (String(key) === '2') {
      dispatch({type: 'global/logout'})
    }
  };

  // Scroll to top
  componentDidUpdate(prevProps) {
    if (this.props.location !== prevProps.location) {
      window.scrollTo(0, 0);
    }
  }

  render() {
    const {menus, loading, children, location, global} = this.props;
    if (loading.effects['global/getProfile']) {
      return <Loading fullScreen spinning={true}/>
    } else {
      if (location.pathname === '/login') {
        return children
      }
      return (
        <Layout className={styles.layout}>
          <Sider menus={menus} pathname={location.pathname} collapsed={this.state.collapsed}/>
          <Layout style={{overflow: 'hidden', height: '100vh'}}>
            <Header toggle={this.toggle} collapsed={this.state.collapsed} onMenuClick={this.onHeaderMenuClick}
                    user={global.user}/>
            <Content className={styles.content}>
              {children}
            </Content>
            <Footer/>
          </Layout>
        </Layout>);
    }
  }
}

All 4 comments

菜单权限,你可以写全局model啊,
我的类似这种:

import {getProfile, logout} from '~services/global';

export default {
  namespace: 'global',
  state: {
    user: {}
  },
  reducers: {
    changeUserInfo(state, {payload}) {
      state.user = payload.user;
      return state;
    }
  },
  effects: {
    * getProfile(actions, {call, put}) {
      try {
        const res = yield call(getProfile);
        yield put({type: 'changeUserInfo', payload: {user: res.profile}})
      } catch (e) {
        window.location.href = '/login';
      }
    },

    * logout(actions, {call, put}) {
      let res = yield call(logout);
      console.log(res);
      window.location.href = '/login'
    }

  },
  subscriptions: {
    setup({dispatch, history}) {
      const {location: {pathname}} = history;
      if (pathname !== '/login') {
        dispatch({type: 'getProfile'})
      }
    }
  },

}

这里的user即当前登录者,包含从api获取的信息(例如:name, account, permission, isAdmin, isMaster, ...)

然后在layout就可以获取到权限了呀
layout/index.js:

import {Layout} from 'antd';

import {connect} from 'dva';
import React from 'react';
import styles from './index.less';
import Header from './Header';
import Footer from './Footer';
import Sider from './Sider';
import withRouter from 'umi/withRouter';
import Loading from '~components/Loading';

const {Content} = Layout;

const mapState2props = ({global, loading}) => {
  return {
    global,
    loading,
    menus: global.user.permission
  }
};

@withRouter
@connect(mapState2props)
export default class NdLayout extends React.PureComponent {
  state = {
    collapsed: false
  };
  toggle = () => {
    this.setState({
      collapsed: !this.state.collapsed
    })
  };
  onHeaderMenuClick = ({key}) => {
    const {dispatch} = this.props;
    if (String(key) === '2') {
      dispatch({type: 'global/logout'})
    }
  };

  // Scroll to top
  componentDidUpdate(prevProps) {
    if (this.props.location !== prevProps.location) {
      window.scrollTo(0, 0);
    }
  }

  render() {
    const {menus, loading, children, location, global} = this.props;
    if (loading.effects['global/getProfile']) {
      return <Loading fullScreen spinning={true}/>
    } else {
      if (location.pathname === '/login') {
        return children
      }
      return (
        <Layout className={styles.layout}>
          <Sider menus={menus} pathname={location.pathname} collapsed={this.state.collapsed}/>
          <Layout style={{overflow: 'hidden', height: '100vh'}}>
            <Header toggle={this.toggle} collapsed={this.state.collapsed} onMenuClick={this.onHeaderMenuClick}
                    user={global.user}/>
            <Content className={styles.content}>
              {children}
            </Content>
            <Footer/>
          </Layout>
        </Layout>);
    }
  }
}

问题1:,/users和/users/child是两个不同的路由,现在没有这样嵌套监听的概念,我觉得可以监听/users/child,判断是否有数据,没有要再发起一起请求。
问题2:可以关注一下https://github.com/umijs/umi/issues/1051

@dawnChen666 参考实验用例https://github.com/xiaohuoni/umi-antd-pro

Was this page helpful?
0 / 5 - 0 ratings