我們知道,當下最火的前端框架,非螞蟻金服的 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許可權控制、動態選單的生成