Ant-Design-Pro-V5: 动态获取配置菜单。

1. 添加获取菜单请求(services/api.ts)

  export async function currentUserMenus() {
    return request<MenuDataItem[]>('/api/org/getUserMenus', {
      method: 'GET',
    });
  }

2. 修改app.tsx文件

2.1 修改getInitialState方法

  export async function getInitialState(): Promise<{
    settings?: Partial<LayoutSettings>;
    currentUser?: API.CurrentUser;
    menuData?: MenuDataItem[] | undefined;
    fetchUserInfo?: () => Promise<API.CurrentUser | undefined>;
    fetchUserMenus?: () => Promise<MenuDataItem[] | undefined>;
  }> {
    const fetchUserInfo = async () => {
      try {
        const currentUser = await queryCurrentUser();
        return currentUser;
      } catch (error) {
        history.push(loginPath);
      }
      return undefined;
    };
    const fetchUserMenus = async () => {
      try {
        const menuData = await queryCurrentUserMenus();
        return menuData;
      } catch (error) {
        history.push(loginPath);
      }
      return undefined;
    };
    // 如果是登录页面,不执行
    if (history.location.pathname !== loginPath) {
      const token = localStorage.getItem('userToken');
      if (!token) {
        history.push(loginPath);
        return {
          fetchUserInfo,
          fetchUserMenus,
          menuData: [],
          settings: {},
        };
      }

      const currentUser = await fetchUserInfo();
      const menuData = await fetchUserMenus();
      return {
        fetchUserInfo,
        fetchUserMenus,
        currentUser,
        menuData,
        settings: {},
      };
    }
    return {
      fetchUserInfo,
      fetchUserMenus,
      menuData: [],
      settings: {},
    };
  }

2.2 修改layout方法

  export const layout: RunTimeLayoutConfig = ({ initialState }) => {
    return {
      rightContentRender: () => <RightContent />,
      disableContentMargin: false,
      waterMarkProps: {
        content: initialState?.currentUser?.name,
      },
      footerRender: () => <Footer />,
      onPageChange: () => {
        console.log('onPageChange');
        const { location } = history;
        // 如果没有登录,重定向到 login
        const token = localStorage.getItem('userToken');
        if (!token && location.pathname !== loginPath) {
          history.push(loginPath);
        }
      },
      links: isDev
        ? [
            <Link to="/umi/plugin/openapi" target="_blank">
              <LinkOutlined />
              <span>openAPI 文档</span>
            </Link>,
            <Link to="/~docs">
              <BookOutlined />
              <span>业务组件文档</span>
            </Link>,
          ]
        : [],
      menuHeaderRender: undefined,
      // menuDataRender: (menuData) => initialState?.menuData || menuData,
      // 显示菜单(带icon)
      menuDataRender: () => {
        return fixMenuItemIcon(initialState?.menuData);
      },
      // menuDataRender: () => menuDataRender(),
      // 自定义 403 页面
      // unAccessible: <div>unAccessible</div>,
      ...initialState?.settings,
    };
  };

3. 解决菜单icon显示问题

创建fixMenuItemIcon.ts组件

 import React from 'react';
  import type { MenuDataItem } from '@ant-design/pro-layout';
  import * as allIcons from '@ant-design/icons';

  const fixMenuItemIcon = (menus: MenuDataItem[], iconType = 'Outlined'): MenuDataItem[] => {
    menus.forEach((item) => {
      const { icon, children } = item;
      if (typeof icon === 'string') {
        const fixIconName = icon.slice(0, 1).toLocaleUpperCase() + icon.slice(1) + iconType;
        // eslint-disable-next-line no-param-reassign
        item.icon = React.createElement(allIcons[fixIconName] || allIcons[icon]);
      }
      // eslint-disable-next-line no-param-reassign,@typescript-eslint/no-unused-expressions
      children && children.length > 0 ? (item.children = fixMenuItemIcon(children)) : null;
    });
    return menus;
  };

  export default fixMenuItemIcon;

4. 登录模块

4.1 登录,登录成功后获取用户信息并保存token

  const handleSubmit = async (values: API.LoginParams) => {
    setSubmitting(true);
    try {
      // 登录
      const msg = await login({ ...values });
      if (msg.data.state === 'ok') {
        message.success('登录成功!');
        localStorage.setItem('userToken', msg.data.token);
        await fetchUserInfo();
        goto();
        return;
      }
      // 如果失败去设置用户错误信息
      setUserLoginState(msg);
    } catch (error) {
      message.error('登录失败,请重试!');
    }
    setSubmitting(false);
  };

4.2 获取用户信息和用户菜单

  const fetchUserInfo = async () => {
    const userInfo = await initialState?.fetchUserInfo?.();
    // 有用户信息 设置初始参数
    if (userInfo) {
      const menus = await initialState?.fetchUserMenus?.();
      setInitialState({
        ...initialState,
        currentUser: userInfo,
        menuData: menus,
      });
    }
  };

5. 注意事项

  1. 菜单返回json格式,字段只需要有path和name就可以了,path地址需要在路由里面有对应的地址:
[
  {
    "icon": "smile",
    "path": "/system",
    "name": "system",
    "children": [
      {
        "icon": null,
        "path": "/system/empty",
        "name": "empty"
      },
      {
        "icon": "smile",
        "path": "/system/rolelist",
        "name": "rolemanage"
      }
    ]
  }
]
  1. 路由文件routes.tsx
export default [
  {
 path: '/user',
 layout: false,
 routes: [
      {
 path: '/user',
 routes: [
          {
 name: 'login',
 path: '/user/login',
 component: './user/Login',
          },
        ],
      },
    ],
  },
  {
 path: '/welcome',
 name: 'welcome',
 icon: 'smile',
 component: './welcome',
  },
  {
 path: '/system',
 routes: [
      {
 icon: 'smile',
 path: '/system/empty',
 component: './sysManage/Empty',
      },
      {
 icon: 'smile',
 path: '/system/rolelist',
 component: './sysManage/RoleManage',
      },
    ],
  },
  {
 path: '/',
 redirect: '/welcome',
  },
  {
 component: './404',
  },
];

如果config/routes.ts 中配置了的菜单,但Menu中没有,是可以通过输入理由名称访问页面的,可以在app.ts中onPageChange方法加上一句:

onPageChange: () => {
   const { location } = umi.history
     // 如果没有登录,重定向到 login
     if (!initialState?.currentUser?.name && location.pathname !== loginPath) {
       umi.history.push(loginPath)
     }
     // 如果訪問頁面不在menuData中。重定向至404.防止在地址欄輸入路由名稱進入頁面
     if (initialState?.menuData?.length && location.pathname !== loginPath) {
       const isInMenu = initialState.menuData.find(item => item.path === location.pathname)
       if (!isInMenu) umi.history.push('/404')
   }
}
// 由于菜单配置一般采用中文 关闭菜单国际化 
menu: {
 locale: false  // 关闭左侧菜单国际化
},
  • 2
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值