thanks

我们知道,当下最火的前端框架,非蚂蚁金服的AntDesign莫属,这个框架不仅在国内非常有名,在国外GitHub上React前端框架也排名第一。而且这个框架涵盖了React、Vue、Angular等多种语言,甚至有人结合.net Core 5的新特性WebAssembly做了Ant Design Blazor,在此为国人点赞!

公司的新平台,用户前端界面当仁不让地使用了AntDesign for React,可以使用最新版本的特性(目前版本为4.10.1);至于为什么不使用Ant Design Pro,是因为Pro封装的控件太多,不利于我们自定义页面。

SAAS系统,页面上首先就是权限,我们后台采用中等复杂度的RBAC控制,如图所示:

在界面上表示,就是程序左侧的树状菜单,参照AntdPro的官方文档,路由和菜单,需要在菜单的ts文档中写清楚各种权限组和相应菜单,显然不符合我们前后端分离使用动态菜单的方法。

因此,我研究一段时间,终于找到完全在后端生成动态菜单并且在前端的使用方法,特此分享给大家。

传递到前端的菜单实体类:

1     public class 菜单实体类
2     {
3         public string key { get; set; }
4         public string icon { get; set; }
5         public string title { get; set; }
6         public string link { get; set; }
7         public IEnumerable<PortalMenu> children { get; set; }
8     }

实际上是一个递归结构的json字符串:

  1 {
  2     "returnCode": 0,
  3     "errorMsg": null,
  4     "data": {
  5         "portalMenus": [{
  6             "key": "R0HGQWqTzE9gzg",
  7             "icon": "DashboardOutlined",
  8             "title": "查询",
  9             "link": "/Wuire",
 10             "children": []
 11         }, {
 12             "key": "g9asSJsw9yx6w",
 13             "icon": "HomeOutlined",
 14             "title": "管理",
 15             "children": [{
 16                 "key": "GBvD0rfpsYa6w",
 17                 "title": "设定",
 18                 "link": "/Willage",
 19                 "children": []
 20             }, {
 21                 "key": "L3LD2SrK84g",
 22                 "title": "管理",
 23                 "link": "/Wuse",
 24                 "children": []
 25             }, {
 26                 "key": "Wdvue6w",
 27                 "title": "管理",
 28                 "link": "/Wner",
 29                 "children": []
 30             }]
 31         }, {
 32             "key": "R3JvXJWQk6d6A",
 33             "icon": "ContactsOutlined",
 34             "title": "",
 35             "children": [{
 36                 "key": "IIJCXkQfPyzg",
 37                 "title": "群发",
 38                 "children": [{
 39                     "key": "hnhrfYWq29w",
 40                     "title": "邮件",
 41                     "link": "/Wend",
 42                     "children": []
 43                 }, {
 44                     "key": "gF7a1XnHQ",
 45                     "title": "群板",
 46                     "link": "/Wdule",
 47                     "children": []
 48                 }, {
 49                     "key": "a8yaA-u6PNQ",
 50                     "title": "历史",
 51                     "link": "/Wtory",
 52                     "children": []
 53                 }]
 54             }, {
 55                 "key": "CI03foxpw",
 56                 "title": "群发",
 57                 "children": [{
 58                     "key": "giaPpeiEoY1Rg",
 59                     "title": "短信",
 60                     "link": "/Wend",
 61                     "children": []
 62                 }, {
 63                     "key": "ewpJBHTcZLjutGQ",
 64                     "title": "模板",
 65                     "link": "/Wuodule",
 66                     "children": []
 67                 }, {
 68                     "key": "0B3qVuvVXpA",
 69                     "title": "历史",
 70                     "link": "/Wtory",
 71                     "children": []
 72                 }]
 73             }, {
 74                 "key": "7foEYA",
 75                 "title": "信印",
 76                 "link": "/Wurint",
 77                 "children": []
 78             }]
 79         }, {
 80             "key": "f3l981rYVQ",
 81             "icon": "PayCircleOutlined",
 82             "title": "费",
 83             "children": [{
 84                 "key": "DIw69fx0d3Q",
 85                 "title": "每",
 86                 "link": "/Wufei",
 87                 "children": []
 88             }, {
 89                 "key": "PBLCWp73mUV8kA",
 90                 "title": "收定",
 91                 "link": "/WMonth",
 92                 "children": []
 93             }, {
 94                 "key": "jT8bbGMc5EVIw",
 95                 "title": "定",
 96                 "link": "/Wting/ShowfeiXiangmu",
 97                 "children": []
 98             }, {
 99                 "key": "eUsfeeeOzbw",
100                 "title": "表",
101                 "link": "/Wufei/Daily",
102                 "children": []
103             }]
104         }, {
105             "key": "RsLTvHziej3eeg",
106             "icon": "ToolOutlined",
107             "title": "理",
108             "children": [{
109                 "key": "jTqs3ne_FJSxqg",
110                 "title": "报",
111                 "link": "/WuAdd",
112                 "children": []
113             }, {
114                 "key": "GTJetl8mFEQ",
115                 "title": "馈",
116                 "link": "/Wudback",
117                 "children": []
118             }, {
119                 "key": "MFtdebYGvg",
120                 "title": "询",
121                 "link": "/Wuyu/Inquire",
122                 "children": []
123             }]
124         }, {
125             "key": "OTzJmw",
126             "icon": "MailOutlined",
127             "title": "理",
128             "children": [{
129                 "key": "5x9__uzbmQ",
130                 "title": "发息",
131                 "link": "/Managend",
132                 "children": []
133             }, {
134                 "key": "D6dGz0J-u98iGXw",
135                 "title": "盒",
136                 "link": "/Manage/Inbox",
137                 "children": []
138             }, {
139                 "key": "xNE-jOp4khOHQ",
140                 "title": "群发",
141                 "link": "/ManagpSend",
142                 "children": []
143             }, {
144                 "key": "DbIxzw6Q",
145                 "title": "群发",
146                 "link": "/ManaSend",
147                 "children": []
148             }, {
149                 "key": "JRO7RUL54zaQ",
150                 "title": "群发",
151                 "link": "/ManaoupSend",
152                 "children": []
153             }]
154         }, {
155             "key": "rKYgJZdxqQ",
156             "icon": "TeamOutlined",
157             "title": "用理",
158             "children": [{
159                 "key": "VpTCpsvOsFyUZQ",
160                 "icon": "UserOutlined",
161                 "title": "管理",
162                 "link": "/Mar/List",
163                 "children": []
164             }, {
165                 "key": "YVaswUMx3g",
166                 "icon": "ClusterOutlined",
167                 "title": "部管理",
168                 "link": "/Manist",
169                 "children": []
170             }, {
171                 "key": "nYIdFQ9K0fiNiw",
172                 "icon": "TeamOutlined",
173                 "title": "用管理",
174                 "link": "/MapList",
175                 "children": []
176             }, {
177                 "key": "5cFzOGcLIQ",
178                 "icon": "KeyOutlined",
179                 "title": "用管理",
180                 "link": "/Manage/UsAuthority",
181                 "children": []
182             }]
183         }, {
184             "key": "ab6MCJ9hNUOIfC5ofROgOw",
185             "icon": "SettingOutlined",
186             "title": "系统设置",
187             "children": [{
188                 "key": "PUGYrEbEZ6Q",
189                 "title": "基本设置",
190                 "link": "/Manaasic",
191                 "children": []
192             }, {
193                 "key": "ueve6vGuOGKD8w",
194                 "title": "域名设置",
195                 "link": "/Manas/Domain",
196                 "children": []
197             }]
198         }, {
199             "key": "46lZGOCDyk6saVYzZwdsJA",
200             "icon": "FileTextOutlined",
201             "title": "日志管理",
202             "children": [{
203                 "key": "ZPi2io3l_EGATyr-9KFk2A",
204                 "title": "系统日志",
205                 "link": "/Manage/Log/Sys",
206                 "children": []
207             }, {
208                 "key": "Ze8mGMsbmkKTXtPQ",
209                 "title": "操作日志",
210                 "link": "/Manage/Log/Operate",
211                 "children": []
212             }]
213         }],
214         "defaultMenuId": "RTzE9gzg"
215     }
216 }

 

前端页面接收后,处理下一二三级菜单,加上图标,就可以渲染出来了:

 1 ......
 2 
 3   state = {
 4     collapsed: false,
 5     openKeys: [],
 6     menus: null,
 7     defaultMenuId: null,
 8   };
 9 
10   async componentDidMount() {
11     var menus = await getUserMenus();
12     var allMenus = await this.getSubMenus(menus.portalMenus);
13     this.setState({ menus: allMenus, defaultMenuId: menus.defaultMenuId });
14   }
15 
16   getSubMenus = (children) =>{
17     let menuInfo = [];
18     children.forEach(ele=>{
19       if (ele.children && ele.children.length > 0) {
20         menuInfo.push(<SubMenu key={ele.key} title={ele.title} icon={GetIconByName(ele.icon)}>{this.getSubMenus(ele.children)}</SubMenu>);
21       } else {
22         menuInfo.push(<Menu.Item key={ele.key} icon={GetIconByName(ele.icon)}><Link to={ele.link}>{ele.title}</Link></Menu.Item>);
23       }
24     });
25     return menuInfo;
26   };
27 
28   render() {
29     return (
30       <Router>
31         <Layout>
32           <Sider trigger={null} collapsible collapsed={this.state.collapsed}>
33             <div className="logo">
34               .
35             </div>
36             <Menu theme="dark" mode="inline"
37               defaultSelectedKeys = {[this.state.defaultMenuId]}
38               openKeys={this.state.openKeys}
39               onOpenChange={this.onOpenChange}>
40               {this.state.menus}
41             </Menu>
42           </Sider>
43 ......

至此,左边的菜单就按照每个人的不同权限渲染出来了。

附:前端的getUserMenus和Comm方法:

 1 //用户取菜单
 2 async function getUserMenus() {
 3     var result = await Comm(....);    
 4     return result.data;
 5 }
 6 
 7 async function Comm(code, ...){
 8   var body = {};
 9   body.Code = code;
10   body.data = ...;
11 
12   var cookie = getCookie(global.......);
13   var headers = {};
14   headers["Content-Type"] = 'application/json';
15   if(cookie){
16     headers.token = cookie;
17   }
18   
19   const response = await fetch(global.webApiUrl,{
20       method: 'POST', 
21       body: JSON.stringify(body), 
22       headers: new Headers(headers)
23     });
24   const rep = await response.json();
25   return rep;
26 }

 

    SAAS云平台搭建札记系列文章:

    SAAS云平台搭建札记: (一)浅论SAAS多租户自助云服务平台的产品、服务和订单

    SAAS云平台搭建札记: (二)Linux Unbutu下.Net Core整套运行环境的搭建

    SAAS云平台搭建札记: (三) AntDesign + .Net Core WebAPI权限控制、动态菜单的生成

相关文章: