我们知道,当下最火的前端框架,非蚂蚁金服的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权限控制、动态菜单的生成

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

  1. SAAS云平台搭建札记: (四) AntD For React使用react-router-dom路由接收不同参数页面不刷新的问题

    在.net开发员眼里,如果使用MVC,根据路由匹配原则,可以通过各种方式接收参数,比如 /Post/List/1, /Post/List/2,或者 /Post/List?id=1,/Post/List ...

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

    最近在做一个多租户的云SAAS软件自助服务平台,途中遇到很多问题,我会将一些心得.体会逐渐分享出来,和大家一起探讨.这是本系列的第一篇文章. 大家知道,要做一个全自助服务的SAAS云平台是比较复杂的, ...

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

    最近做的项目,由于预算有限,公司决定不采购Windows服务器,而采购基于Linux的服务器. 一般的VPS服务器,如果使用Windows系统,那么Windows Server2012\2016安装好 ...

  4. Redis之高可用、集群、云平台搭建

    原文:Redis之高可用.集群.云平台搭建 文章大纲 一.基础知识学习二.Redis常见的几种架构及优缺点总结三.Redis之Redis Sentinel(哨兵)实战四.Redis之Redis Clu ...

  5. Docker系列——InfluxDB+Grafana+Jmeter性能监控平台搭建(三)

    在之前系列博文中,已经介绍完了数据采集和数据存储,那数据如何展示呢?所以今天就专门来讲下数据如何展示的问题. 以前博文参考: Docker系列--InfluxDB+Grafana+Jmeter性能监控 ...

  6. Redis之高可用、集群、云平台搭建(非原创)

    文章大纲 一.基础知识学习二.Redis常见的几种架构及优缺点总结三.Redis之Redis Sentinel(哨兵)实战四.Redis之Redis Cluster(分布式集群)实战五.Java之Je ...

  7. 三种SpringSecurity方法级别权限控制

    一 JSR-250注解 1.在pom.xml添加 <dependency> <groupId>javax.annotation</groupId> <arti ...

  8. .net core3.1 abp动态菜单和动态权限(动态菜单实现和动态权限添加) (三)

    我们来创建动态菜单吧 首先,先对动态菜单的概念.操作.流程进行约束:1.Host和各个Tenant有自己的自定义菜单2.Host和各个Tenant的权限与自定义菜单相关联2.Tenant有一套默认的菜 ...

  9. Jmeter+ant+jenkins接口自动化测试 平台搭建(三)

    四.报告优化 Jmeter 默认生成报告不是很详细,因此我们需要进行优化.这里我们使用新的报告模板:默认的报告模板是 jmeter-results-detail-report_21.xsl 先上效果图 ...

随机推荐

  1. Server returns invalid timezone. Go to 'Advanced' tab and set 'serverTimezone' property manually.

    用pycharm连接mysql报错 改变serverTimezone 改了之后确实可以连接上mysql数据库

  2. javascript编写原则

    1.不要在同一行声明多个变量2.使用===或!==来比较3.使用字面量的方式来创建对象.数组,替代new Array这种形式4.switch语句必须要带default分支5.fon-in循环中的变量, ...

  3. ip 子网掩码、网络地址、广播地址计算

    例:已知ip  16.158.165.91/22子网掩码 根据22 得知子网掩码占22位 即:11111111.11111111.11111100.00000000   == 255.255.252. ...

  4. Springboot mini - Solon详解(一)- 快速入门

    一.Springboot min -Solon 最近号称 Springboot mini 的 Solon框架,得空搞了一把,发觉Solon确实好用,小巧而快速.那Solon到底是什么,又是怎么好用呢? ...

  5. Mysql为什么使用b+树,而不是b树、AVL树或红黑树?

    首先,我们应该考虑一个问题,数据库在磁盘中是怎样存储的?(答案写在下一篇文章中) b树.b+树.AVL树.红黑树的区别很大.虽然都可以提高搜索性能,但是作用方式不同. 通常文件和数据库都存储在磁盘,如 ...

  6. uniapp保存图片到本地(APP和微信小程序端)

    uniapp实现app端和微信小程序端图片保存到本地,其它平台未测过,原理类似. 微信小程序端主要是权限需要使用button的开放能力来反复调起,代码如下: 首先是条件编译两个平台的按钮组件: < ...

  7. C++异常之七 标准库里的异常类

    标准库里的异常类 C++标准提供了一组标准异常类,这些类以基类 Exception 开始,标准程序库抛出的所有异常,都派生于该基类,这些类构成如图所示的异常类的派生继承关系,该基类提供一个成员函数 w ...

  8. eclipse提示JVM版本太低

    解决方案:去eclipse的安装路径找到eclipse.ini文件,然后在头部指定JVM的版本(第一第二行) -vm C:/Program Files/Java/jdk-11.0.9/bin -sta ...

  9. Docker(二):Docker镜像仓库Harbor搭建

    安装docker-compose 因为docker-compose下载容易失败, 所以选择从github下载方式安装. [root@harbor ~]# mv docker-compose-Linux ...

  10. Ubuntu系统升级

    转自:Ubuntu14.04升级到18.04 查看当前版本 lsb_release -a 执行更新 apt-get update apt-get upgrade apt dist-upgrade 重启 ...