antd pro 服务端获取菜单及设置路由

app.tsx RunTimeLayoutConfig 运行时配置

关键代码1:值为后台获取的真实菜单及路由信息
initialState?.currentUser?.menus 为项目登录初始化后设置的菜单,此处可以在getInitialState
中进行设置,对后台的菜单进行处理,转换为antd 的格式

menuDataRender: () =>initialState?.currentUser?.menus,

关键代码2: routes.ts 一定要设置好路由和组件对应关系,不然就算获取到路由,访问的时候组件也是404页面, hideInMenu为true, 隐藏目录,通过后台获取菜单及路由

{
    name: 'Home1',
    icon: 'smile',
    hidden: false,
    hideInMenu: false,
    path: '/Numbers',
    // component: BasicLayout,
    // layout: true,
    // redirect: '/Numbers/NumbersModel',
    routes: [
      {
        name: 'home',
        icon: 'smile',
        hidden: false,
        hideInMenu: false,
        path: '/Numbers/NumbersModel',
        component: './Numbers/NumbersModel',
      },
    ],
  },

一级菜单icon实现代码

// 封装处理一级菜单方法

mport type { MenuDataItem } from '@ant-design/pro-layout';
import { createFromIconfontCN, SmileOutlined, HeartOutlined, BugOutlined } from '@ant-design/icons';
// 引入多个iconfot, 本地及远程
const IconFont = createFromIconfontCN({
  scriptUrl: [
    require('../../assets/iconfont/iconfont.js'),
    '//at.alicdn.com/t/font_xxxx.js',
  ],
});

const IconMap = {
  smile: <SmileOutlined />,
  heart: <HeartOutlined />,
  index: <IconFont type="icon-index" style={{ color: '#08c' }} />,
  basic: <IconFont type="icon-basic" />,
  bug: <BugOutlined />,
  clockorder2: <IconFont type="icon-clockorder2" />,
  report2: <IconFont type="icon-report2" />,
  map: <IconFont type="icon-map" />,
  data: <IconFont type="icon-data" />,
  dict: <IconFont type="icon-dict" />,
}

export const loopMenuItem = (menus: MenuDataItem[]): MenuDataItem[] =>
  menus.map(({ icon, routes, ...item }) => ({
    ...item,
    icon: icon && IconMap[icon as string],
    routes: routes && loopMenuItem(routes), //递归调用
  }));

二级菜单icon 实现逻辑

   menuItemRender: (menuItemProps, defaultDom) => {
      if (menuItemProps.isUrl || !menuItemProps.path) {
        return defaultDom;
      }
      return (
        <Link to={menuItemProps.path} >
          {menuItemProps.pro_layout_parentKeys && menuItemProps.pro_layout_parentKeys.length > 0 && menuItemProps.icon}
          {defaultDom}
        </Link>
      )
    },

附1:RunTimeLayoutConfig配置

export const layout: RunTimeLayoutConfig = ({ initialState, setInitialState }) => {
  console.log('initialState', initialState);
  return {
    rightContentRender: () => <RightContent />,
    disableContentMargin: false,
    waterMarkProps: {
      content: initialState?.currentUser?.name
    },
    footerRender: () => <Footer />,
    onPageChange: () => {
      const { location } = history;
      // 如果没有登录,重定向到 login
      if (!initialState?.currentUser && location.pathname !== loginPath) {
        history.push(loginPath);
      }
    },
    links: isDev
      ? [
        <Link key="openapi" to="/umi/plugin/openapi" target="_blank">
          <LinkOutlined />
          <span>OpenAPI 文档</span>
        </Link>,
        <Link to="/~docs" key="docs">
          <BookOutlined />
          <span>业务组件文档</span>
        </Link>,
      ]
      : [],
    menuHeaderRender: undefined,
    menuDataRender: () => initialState?.currentUser?.menus,
    // menu: () => loopMenuItem(initialState?.currentUser?.menus),
    // 二级icon
    menuItemRender: (menuItemProps, defaultDom) => {
      if (menuItemProps.isUrl || !menuItemProps.path) {
        return defaultDom;
      }
      return (
        <Link to={menuItemProps.path} >
          {menuItemProps.pro_layout_parentKeys && menuItemProps.pro_layout_parentKeys.length > 0 && menuItemProps.icon}
          {defaultDom}
        </Link>
      )
    },
    // 自定义 403 页面
    // unAccessible: <div>unAccessible</div>,
    // 增加一个 loading 的状态
    childrenRender: (children, props) => {
      // if (initialState?.loading) return <PageLoading />;
      return (
        <>
          {children}
          {!props.location?.pathname?.includes('/login') && (
            <SettingDrawer
              disableUrlParams
              enableDarkTheme
              settings={initialState?.settings}
              onSettingChange={(settings) => {
                setInitialState((preInitialState) => ({
                  ...preInitialState,
                  settings,
                }));
              }}
            />
          )}
        </>
      );
    },
    ...initialState?.settings,
  };
};

附二:获取菜单和用户信息

// 获取用户及菜单
const fetchUserInfo = async () => {
  try {
    // const msg = await queryCurrentUser();
    let userInfo = {
      name: 'Serati Ma',
      avatar: 'https://gw.alipayobjects.com/zos/antfincdn/XAosXuNZyF/BiazfanxmamNRoxxVxka.png',
      userid: '00000001',
      access: 'user',
    };
    const msg = await queryCurrentUserInfo();
    // 先把菜单处理造出来
    const menus = TreeDataTranslate(msg.obj.menus);
    const newMenus = fetchRouter(menus, 1);
    const fullMenus = routes.concat(newMenus);
    const fullIcons = loopMenuItem(fullMenus);
    console.log('menus', menus)
    console.log('menus1', newMenus)
    // console.log('fullMenus', fullMenus)
    msg.data = { ...msg.obj, ...userInfo, menus: fullIcons }
    // msg.data = { ...msg.obj, ...userInfo }
    console.log('userInfo', msg);
    return msg.data;
  } catch (error) {
    history.push(loginPath);
  }
  return undefined;
};

附三:转换服务端获取的菜单

/**
 * 
 * @param {*} [
    {
        "id": 301,
        "cat": "0",
        "code": "userauth", // 路由name
        "icon": "role", // 路由图标
        "isLeaf": "T", 
        "isShow": "T",  // 是否显示
        "name": "用户权限",
        "parentId": 0,
        "sortOrder": 999
    },
    {
        "id": 302,
        "cat": "1",
        "code": "user",
        "icon": "data",
        "isLeaf": "T",
        "isShow": "T",
        "name": "用户管理",
        "parentId": 301, // 父级菜单id
        "sortOrder": 999
    },
    {
        "id": 303,
        "cat": "1",
        "code": "role",
        "icon": "data",
        "isLeaf": "T",
        "isShow": "T",
        "name": "角色",
        "parentId": 301,
        "sortOrder": 999
    },
  ] 
 * @param {*} id 
 * @param {*} pid // 
 * @returns 
 */
export function TreeDataTranslate(data, id = 'id', pid = 'parentId') {
  let res = [];
  let temp = {};
  for (let i = 0; i < data.length; i++) {
    temp[data[i][id]] = data[i];
  }
  for (let k = 0; k < data.length; k++) {
    if (temp[data[k][pid]] && data[k][id] !== data[k][pid]) {
      if (!temp[data[k][pid]]['routes']) {
        temp[data[k][pid]]['routes'] = [];
      }
      if (!temp[data[k][pid]]['_level']) {
        temp[data[k][pid]]['_level'] = 1;
      }
      data[k]['_level'] = temp[data[k][pid]]._level + 1;
      data[k]['pCode'] = temp[data[k][pid]].code;
      temp[data[k][pid]]['routes'].push(data[k]);
    } else {
      res.push(data[k]);
    }
  }
  return res;
}

export function TreeDataTranslate2(data, level) {
  if (data) {
    for (let k = 0; k < data.length; k++) {
      data[k]['_level'] = level;
      if (data[k]['routes'] && data[k]['routes'].length > 0) {
        TreeDataTranslate2(data[k]['routes'], level + 1);
      }
    }
  }
}

export function fetchRouter(arr, level) {
  let ret = [];
  arr.forEach((menu) => {
    let item = {};
    item.name = menu.code;
    item.icon = menu.icon || 'smile';
    item.hidden = menu.isShow != 'T';
    item.hideInMenu = menu.isShow != 'T';
    // item.exact = true;
    if (menu.cat == 0) {
      item.redirect = 'noredirect';
      item.path = '/' + menu.code;
      item.component = './' + menu.code
      console.log('icon level :>> ', menu.icon, item.icon);
    } else {
      item.component = './' + menu.pCode + '/' + menu.code
      item.path = '/' + menu.pCode + '/' + menu.code;
    }
    if (menu.routes) {
      item.routes = fetchRouter(menu.routes, level + 1);
    }
    ret.push(item);
  });
  return ret;
}

参考:antd pro V5从服务端请求菜单

  • 1
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
### 回答1: 要设置动态菜单,你需要在 Ant Design Pro 中使用路由配置来定义你的菜单。在路由配置中,你可以为每个页面定义一个菜单项,并且可以根据需要设置它们的子菜单。 以下是一个简单的例子,展示如何使用路由配置来设置动态菜单: ```javascript // src/config/router.config.js export default [ { path: '/dashboard', name: 'Dashboard', icon: 'dashboard', component: './Dashboard', }, { path: '/users', name: 'Users', icon: 'user', component: './Users', }, { path: '/settings', name: 'Settings', icon: 'setting', routes: [ { path: '/settings/profile', name: 'Profile', component: './Profile', }, { path: '/settings/account', name: 'Account', component: './Account', }, ], }, ]; ``` 在上面的配置中,我们定义了三个顶级菜单项:Dashboard、Users 和 Settings。Settings 菜单项有两个子菜单项:Profile 和 Account。 然后,我们需要将这些路由配置传递给 ProLayout 组件,该组件将渲染菜单和其他布局元素: ```javascript // src/layouts/BasicLayout.js import ProLayout from '@ant-design/pro-layout'; import routerConfig from '../config/router.config'; export default function BasicLayout(props) { return ( <ProLayout route={routerConfig} location={props.location} {...props} > {props.children} </ProLayout> ); } ``` 在上面的代码中,我们将路由配置传递给 ProLayout 组件,并将其设置为 `route` 属性的值。这将告诉 ProLayout 组件如何渲染你的菜单。 现在,你可以在你的页面组件中访问 `menuData` 属性,该属性包含有关当前菜单的信息。例如,你可以使用 `menuData` 属性来确定哪个菜单项当前处于活动状态: ```javascript // src/pages/Dashboard.js import { useLocation } from 'umi'; export default function Dashboard() { const location = useLocation(); const activeMenu = location.pathname; return ( <div> <h1>Dashboard</h1> <p>Active menu: {activeMenu}</p> </div> ); } ``` 在上面的例子中,我们使用 `useLocation` 钩子来获取当前页面的位置,并使用它来确定哪个菜单项当前处于活动状态。 ### 回答2: antdpro是一款基于Ant Design的React前端开发框架,可以用来快速搭建UI界面和管理系统。设置动态菜单是指根据用户权限或其他条件,在页面加载时动态生成菜单项。 首先,我们需要从后端获取用户的权限信息或菜单数据。可以通过接口请求获取数据或在登录时将数据存储在本地。 接下来,在Ant Design Pro框架中,可以在config目录下的menu.js文件中配置菜单。这个文件可以定义路由菜单项等信息。在这个文件中,可以使用JavaScript的语法来动态生成菜单项。 例如,可以使用.map()方法遍历权限数据或菜单数据,并根据数据生成菜单项。根据数据的结构,可以设置菜单项的标题、路径、图标等属性。可以根据数据中是否有子菜单的字段,来判断是否需要生成子菜单项。 在菜单项的路径配置中,可以使用动态路由的方式,将菜单项和具体的页面组件相对应。这样,当用户点击菜单项时,就可以跳转到对应的页面。 然后,在布局组件(通常是BasicLayout)中,可以根据菜单的配置信息,使用Ant Design Pro提供的Menu组件来渲染菜单。可以根据路由信息,自动高亮显示当前页面对应的菜单项。 最后,在菜单配置完成后,就可以启动项目,访问页面,就能看到动态生成的菜单了。根据用户的权限或其他条件,在页面加载时,会根据菜单配置自动显示对应的菜单项。 总结起来,通过配置菜单数据,使用Ant Design Pro提供的组件来渲染菜单,再根据用户权限或其他条件动态生成菜单项,就可以实现antdpro设置动态菜单的功能。 ### 回答3: 在antdpro设置动态菜单需要以下步骤: 1. 定义菜单数据:首先,我们需要定义菜单的数据结构。菜单可以使用树形结构,每个节点包含菜单项的信息,比如菜单名称、图标、路由等。 2. 获取菜单数据:接下来,我们需要从后端获取菜单数据。可以使用Ajax或者Fetch等方式从后端获取菜单数据。 3. 将菜单数据存储到状态中:获取菜单数据后,我们需要将数据存储到React组件的状态中。可以使用useState或者useReducer等Hooks来管理菜单数据的状态。 4. 渲染动态菜单:在组件的渲染方法中,使用遍历函数(如map)将菜单数据映射到菜单组件中。antdpro提供了Menu和SubMenu两个组件来渲染菜单结构。可以根据菜单数据的层级关系来嵌套使用这两个组件。 5. 添加路由和点击事件:对于菜单中的每个菜单项,我们通常需要添加路由和点击事件。可以使用React Router来定义路由,同时在点击事件中也可以使用history.push()来实现路由跳转。 6. 权限管理:动态菜单通常还需要与用户的权限管理相结合。可以根据用户的角色或权限设置不同的菜单项显示或隐藏。可以在渲染菜单时,通过条件判断来控制菜单项的显示与隐藏。 以上就是在antdpro设置动态菜单的大致步骤。通过定义菜单数据、获取菜单数据、存储菜单数据、渲染动态菜单以及添加路由和点击事件等步骤,我们可以实现一个灵活、可扩展的动态菜单功能。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值