cfel-base-components 2.5.43 → 2.5.45

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,8 +1,10 @@
1
1
  import React, { useEffect, useState } from 'react'
2
- import { Layout, Menu, MenuProps, Popover } from 'antd'
2
+ import { Layout, List, Menu, MenuProps, Popover } from 'antd'
3
3
  import UserCard from './user-card'
4
+ import { useMemo } from 'react'
5
+ import RcMenu, { SubMenu, MenuItem } from 'rc-menu'
6
+ import { CloseCircleOutlined } from '@ant-design/icons'
4
7
  import './index.scss'
5
-
6
8
  const { Sider } = Layout
7
9
 
8
10
  export interface LiosLayoutlProps {
@@ -10,9 +12,10 @@ export interface LiosLayoutlProps {
10
12
  productCode: string
11
13
  children: any
12
14
  menuList: any
13
- onMenuClick: (item: any) => void
15
+ onMenuClick: any
14
16
  selectedKeys: string[]
15
- customAction?: (item: any) => void
17
+ setSelectKeys: (keys: string[]) => void
18
+ customAction?: any
16
19
  actions?: any[]
17
20
  myWalletInfo?: {
18
21
  availableCashAmount: string
@@ -26,22 +29,23 @@ export interface LiosLayoutlProps {
26
29
  residueNum: string
27
30
  currencyCode: string
28
31
  }
29
- myWalletInfoAction?: Function
30
- myLoginInfoAction?: Function
32
+ myWalletInfoAction?: any
33
+ myLoginInfoAction?: any
31
34
  logoutUrl?: string
32
35
  switchTenantUrl?: string
33
36
  defaultOpenKeys?: string[]
34
37
  isHideHeader?: boolean //是否隐藏header
38
+ onCollapse?: (value: boolean) => void
39
+ type?: string
35
40
  }
36
41
 
37
42
  export default function LiosLayout(props: LiosLayoutlProps) {
38
43
  const {
39
44
  appName,
40
- productCode,
41
45
  menuList,
42
46
  onMenuClick,
43
- selectedKeys,
44
-
47
+ selectedKeys = [],
48
+ setSelectKeys = () => {},
45
49
  customAction,
46
50
  actions,
47
51
 
@@ -52,9 +56,21 @@ export default function LiosLayout(props: LiosLayoutlProps) {
52
56
  myWalletInfoAction,
53
57
  myLoginInfoAction,
54
58
  isHideHeader,
59
+ onCollapse,
60
+ type,
55
61
  } = props
56
62
 
57
- const { user, logo, subLogo } = (window as any)?.g_config
63
+ const logoUrl =
64
+ type === 'console'
65
+ ? 'https://cfel-front.oss-cn-hangzhou.aliyuncs.com/logo/company-logo/cfel-logo-white-compress.png'
66
+ : 'https://cfel-front.oss-cn-hangzhou.aliyuncs.com/logo/company-logo/chengfengerlai.png'
67
+
68
+ const subLogoUrl =
69
+ type === 'console'
70
+ ? 'https://cfel-front.oss-cn-hangzhou.aliyuncs.com/logo/company-logo/chengfengerlai-white.png'
71
+ : 'https://cfel-front.oss-cn-hangzhou.aliyuncs.com/logo/company-logo/chengfengerlai.png'
72
+
73
+ const { user, logo, subLogo, productCode } = (window as any)?.g_config
58
74
  const { name, avatar } = user || {}
59
75
 
60
76
  const [openKeys, setOpenKeys] = useState<any>(defaultOpenKeys || [])
@@ -83,6 +99,7 @@ export default function LiosLayout(props: LiosLayoutlProps) {
83
99
  findNode(menuList, [])
84
100
  return result
85
101
  }
102
+
86
103
  useEffect(() => {
87
104
  //在这里找到当前菜单的上层目录
88
105
  const paMenu = findParentMenu(menuList, '/' + location.pathname.split('/')[2])
@@ -94,7 +111,6 @@ export default function LiosLayout(props: LiosLayoutlProps) {
94
111
  setOpenKeys(Array.from(set))
95
112
  }, [location.pathname])
96
113
 
97
-
98
114
  const [collapsed, setCollapsed] = useState(localStorage.getItem('layout_collapsed') === 'true')
99
115
  const [isCopied, setIsCopied] = useState({
100
116
  account: false,
@@ -114,51 +130,204 @@ export default function LiosLayout(props: LiosLayoutlProps) {
114
130
  } catch (err) {}
115
131
  }
116
132
 
133
+ const style = useMemo(() => {
134
+ if (collapsed) {
135
+ return {
136
+ style: {
137
+ padding: '0',
138
+ paddingTop: '24px',
139
+ },
140
+ }
141
+ } else {
142
+ return {
143
+ style: {},
144
+ }
145
+ }
146
+ }, [collapsed])
147
+
148
+ const collapseNode = () => {
149
+ return {
150
+ height: 0,
151
+ }
152
+ }
153
+ const expandNode = (node: any) => {
154
+ return { height: node.scrollHeight }
155
+ }
156
+
157
+ const inlineMotion = {
158
+ motionName: 'rc-menu-collapse',
159
+ onAppearStart: collapseNode,
160
+ onAppearActive: expandNode,
161
+ onEnterStart: collapseNode,
162
+ onEnterActive: expandNode,
163
+ onLeaveStart: expandNode,
164
+ onLeaveActive: collapseNode,
165
+ }
166
+
167
+ const verticalMotion = {
168
+ motionName: 'rc-menu-open-zoom',
169
+ motionAppear: true,
170
+ motionEnter: true,
171
+ motionLeave: true,
172
+ }
173
+
117
174
  return (
118
- <Layout className="layout-warp">
175
+ <Layout className="layout-warps">
119
176
  {Array.isArray(menuList) && menuList.length > 0 && (
120
177
  <Sider
121
178
  className="layout-side"
122
- style={{
123
- backgroundSize: collapsed ? '1800%' : '900%',
124
- }}
125
179
  collapsible
180
+ trigger={null}
126
181
  collapsed={collapsed}
127
- width={240}
182
+ width={260}
128
183
  onCollapse={(value) => {
184
+ if (onCollapse) {
185
+ onCollapse(value)
186
+ }
129
187
  localStorage.setItem('layout_collapsed', value.toString())
130
188
  setCollapsed(value)
131
189
  }}
132
190
  >
133
- <div
134
- className="layout-logo"
135
- onClick={() => {
136
- window.open('/home')
137
- }}
138
- >
139
- {<img className={`logo-img ${!collapsed ? 'current-logo' : 'hide-logo'}`} src={logo || ''} />}
140
- {
141
- <img
142
- className={`logo-img sub-logo
143
- ${collapsed ? 'current-logo' : 'hide-sub-logo'}`}
144
- src={subLogo || 'https://cdn.chengfengerlai.com/logo/company-logo/chengfengerlai-white.png'}
145
- />
146
- }
191
+ <div className="header-logo" style={{ justifyContent: collapsed ? 'center' : '', paddingLeft: collapsed ? '0' : '' }}>
192
+ <div
193
+ onClick={() => {
194
+ window.open('/home')
195
+ }}
196
+ >
197
+ {!collapsed && <img className={`logo-base current-logo`} src={logo || logoUrl} />}
198
+
199
+ {collapsed && <img className={`logo-base sub-logo`} src={logo || subLogoUrl} />}
200
+ </div>
201
+
202
+ {/* {!collapsed && (
203
+ <div
204
+ className="trigger"
205
+ onClick={() => {
206
+ setCollapsed(true)
207
+ }}
208
+ >
209
+ <Arrow collapsed={true} />
210
+ </div>
211
+ )} */}
212
+ </div>
213
+
214
+ {/* {collapsed && (
215
+ <div style={{ width: '100%', display: 'flex', justifyContent: 'center' }}>
216
+ <div
217
+ className="close-trigger"
218
+ onClick={() => {
219
+ setCollapsed(false)
220
+ }}
221
+ >
222
+ <Arrow collapsed={false} />
223
+ </div>
224
+ </div>
225
+ )} */}
226
+
227
+ <div style={{ height: 24 }}></div>
228
+
229
+ <div style={{ width: '100%', display: 'flex', justifyContent: 'center' }}>
230
+ <Search menuList={menuList} collapsed={collapsed} type={type || ''} />
147
231
  </div>
148
232
 
149
- <div className="layout-menu-container">
150
- <Menu
151
- mode="inline"
233
+ {!collapsed && <div style={{ height: 24 }}></div>}
234
+
235
+ <div className="layout-menu">
236
+ <RcMenu
237
+ mode={collapsed ? 'vertical' : 'inline'}
238
+ className={`menu${collapsed ? '-collapsed' : ''}`}
239
+ motion={collapsed ? verticalMotion : inlineMotion}
152
240
  openKeys={openKeys}
153
241
  onOpenChange={onOpenChange}
154
- items={menuList}
242
+ selectedKeys={selectedKeys}
155
243
  onClick={(item): any => {
156
- onMenuClick && onMenuClick(item)
244
+ setSelectKeys(item.keyPath)
245
+ if (onMenuClick) {
246
+ onMenuClick(item)
247
+ }
157
248
  }}
158
- selectedKeys={selectedKeys}
159
- theme="dark"
160
- color="red"
161
- />
249
+ triggerSubMenuAction="hover"
250
+ >
251
+ {menuList.map((item: any) => {
252
+ const isSelected = selectedKeys.includes(item.key)
253
+ if (item.children) {
254
+ let classNames = 'menu-item-label'
255
+ if (isSelected) {
256
+ classNames += ' submenu-selected'
257
+ }
258
+ return (
259
+ <SubMenu
260
+ popupClassName="rc-menu-submenu-popup"
261
+ key={item.key}
262
+ className="menu-item-content"
263
+ title={
264
+ <div className="sub-list">
265
+ <div className="menu-item-inner">
266
+ <span className={`menu-item-icon ${isSelected ? 'submenu-selected' : ''}`}>{item.icon}</span>
267
+ {!collapsed && <span className={classNames}>{item.label}</span>}
268
+ </div>
269
+ </div>
270
+ }
271
+ >
272
+ {item.children.map((child: any) => {
273
+ const isSelected = selectedKeys.includes(child.key)
274
+ if (item.children) {
275
+ let classNames = 'menu-item-label'
276
+ if (isSelected) {
277
+ classNames += ' submenu-selected'
278
+ }
279
+ }
280
+ if (child.children) {
281
+ return (
282
+ <SubMenu
283
+ popupClassName="rc-menu-submenu-popup"
284
+ className="menu-item-content sub-li"
285
+ key={child.key}
286
+ title={<div className="sub-list">{!collapsed && <span className={`menu-item-label ${isSelected ? 'submenu-selected' : ''}`}>{child.label}</span>}</div>}
287
+ >
288
+ {child.children.map((grandChild: any) => {
289
+ const isSelected = selectedKeys.includes(grandChild.key)
290
+ if (item.children) {
291
+ let classNames = 'menu-item-label'
292
+ if (isSelected) {
293
+ classNames += ' submenu-selected'
294
+ }
295
+ }
296
+ return (
297
+ <MenuItem key={grandChild.key} className="grand-li">
298
+ <div className="menu-item-content">{!collapsed && <span className={`menu-item-label ${isSelected ? 'submenu-selected' : ''}`}>{grandChild.label}</span>}</div>
299
+ </MenuItem>
300
+ )
301
+ })}
302
+ </SubMenu>
303
+ )
304
+ }
305
+ return (
306
+ <MenuItem key={child.key} className="sub-li">
307
+ <div className="menu-item-content">{!collapsed && <span className={`menu-item-label ${isSelected ? 'submenu-selected' : ''}`}>{child.label}</span>}</div>
308
+ </MenuItem>
309
+ )
310
+ })}
311
+ </SubMenu>
312
+ )
313
+ }
314
+ // 没有子菜单的
315
+ else {
316
+ let classNames = 'menu-item-label'
317
+ if (isSelected) {
318
+ classNames += ' submenu-selected'
319
+ }
320
+ return (
321
+ <MenuItem key={item.key} className="menu-item-content">
322
+ <div>
323
+ <span className={`menu-item-icon ${isSelected ? 'submenu-selected' : ''}`}>{item.icon}</span>
324
+ {!collapsed && <span className={classNames}>{item.label}</span>}
325
+ </div>
326
+ </MenuItem>
327
+ )
328
+ }
329
+ })}
330
+ </RcMenu>
162
331
  </div>
163
332
  </Sider>
164
333
  )}
@@ -199,7 +368,9 @@ export default function LiosLayout(props: LiosLayoutlProps) {
199
368
  tenantName: false,
200
369
  tenantId: false,
201
370
  })
202
- myLoginInfoAction && myLoginInfoAction()
371
+ if (myLoginInfoAction) {
372
+ myLoginInfoAction()
373
+ }
203
374
  }}
204
375
  >
205
376
  <div className="layout-header-user">
@@ -214,3 +385,183 @@ export default function LiosLayout(props: LiosLayoutlProps) {
214
385
  </Layout>
215
386
  )
216
387
  }
388
+
389
+ function Arrow({ collapsed }: { collapsed?: boolean }) {
390
+ return (
391
+ <div>
392
+ <svg style={{ transform: !collapsed ? 'rotate(180deg)' : 'rotate(0deg)' }} viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" width="20" height="20">
393
+ <path
394
+ fill="#7D8295"
395
+ d="M564.6336 775.168a41.5744 41.5744 0 0 0-13.312-28.672l-230.4-234.4448 229.9904-234.1888a42.0864 42.0864 0 0 0-26.3168-73.0112 42.0864 42.0864 0 0 0-30.6176 11.264L231.0656 481.024a41.984 41.984 0 0 0-2.4576 59.5968l1.9968 2.048 263.7824 265.6256a41.984 41.984 0 0 0 70.2464-33.0752z m254.5152 0a41.472 41.472 0 0 0-13.312-28.672L575.488 512l229.9904-234.1376a41.984 41.984 0 1 0-56.9344-61.7984L485.632 480.9728a42.0864 42.0864 0 0 0-2.4064 59.6992l0.8704 0.9216 0.8704 0.8192 0.4096 0.4096 263.5776 265.4208a41.984 41.984 0 0 0 70.1952-33.0752z"
396
+ ></path>
397
+ </svg>
398
+ </div>
399
+ )
400
+ }
401
+
402
+ function Search({ menuList, collapsed, type }: { menuList: any; collapsed: boolean; type: string }) {
403
+ useEffect(() => {
404
+ const handleKeyDown = (event: KeyboardEvent) => {
405
+ // Check for Ctrl+K (Windows) or Cmd+K (Mac)
406
+ if ((navigator.platform.toLowerCase().includes('mac') ? event.metaKey : event.ctrlKey) && event.key.toLowerCase() === 'k') {
407
+ event.preventDefault()
408
+ const searchInput = document.querySelector('#menu-input') as HTMLInputElement
409
+ if (searchInput) {
410
+ searchInput.focus()
411
+ setIsHovered(true)
412
+ }
413
+ }
414
+ }
415
+
416
+ document.addEventListener('keydown', handleKeyDown)
417
+ return () => {
418
+ document.removeEventListener('keydown', handleKeyDown)
419
+ }
420
+ }, [])
421
+ type Router = { label: string; icon?: any; key: string; children?: Router[] }
422
+
423
+ const name = (window as any).g_config.productCode
424
+
425
+ const [searchTerm, setSearchTerm] = useState('')
426
+ const [searchHistory, setSearchHistory] = useState<Router[]>([])
427
+ const [searchResult, setSearchResult] = useState<Router[]>([])
428
+ const [isHovered, setIsHovered] = useState(false)
429
+
430
+ useEffect(() => {
431
+ const searchHistory = localStorage.getItem(name + 'searchHistory')
432
+ if (searchHistory) {
433
+ setSearchHistory(JSON.parse(searchHistory))
434
+ } else {
435
+ setSearchHistory([])
436
+ }
437
+ }, [])
438
+
439
+ useEffect(() => {
440
+ if (searchHistory.length > 5) {
441
+ searchHistory.shift()
442
+ }
443
+ localStorage.setItem(name + 'searchHistory', JSON.stringify(searchHistory))
444
+ }, [searchHistory])
445
+
446
+ const handleSearch = (value: string) => {
447
+ setSearchTerm(value)
448
+ //递归menulist判断是否有包含的
449
+ const searchResults: Router[] = []
450
+ search(menuList)
451
+ setSearchResult(searchResults)
452
+ function search(data: Router[]) {
453
+ data.forEach((item) => {
454
+ if (item.label.includes(value.toLocaleUpperCase())) {
455
+ searchResults.push(item)
456
+ }
457
+ if (item.children) {
458
+ search(item.children)
459
+ }
460
+ })
461
+ }
462
+ }
463
+
464
+ const enter = (item: Router) => {
465
+ setIsHovered(false)
466
+ //如果搜索历史里面有这个item,就不再添加
467
+ if (searchHistory.findIndex((i) => i.key === item.key) === -1) {
468
+ setSearchHistory([...searchHistory, item])
469
+ }
470
+ //如果是目录就找到目录下第一个菜单进入
471
+ if (!item.key.includes('/')) {
472
+ //递归找到目录下第一个菜单
473
+ const findFirst = (data: Router[]): Router | undefined => {
474
+ for (let i = 0; i < data.length; i++) {
475
+ if (data[i].key.includes('/')) {
476
+ return data[i]
477
+ } else {
478
+ return findFirst(data[i].children || [])
479
+ }
480
+ }
481
+ }
482
+ const firstItem = findFirst(item.children || [])
483
+ if (firstItem) {
484
+ //history.push(firstItem.key, '_self')
485
+ }
486
+ } else {
487
+ // history.push(item.key, '_self')
488
+ }
489
+ }
490
+
491
+ const deleteHistory = (item: Router) => {
492
+ setSearchHistory(searchHistory.filter((i) => i.key !== item.key))
493
+ }
494
+ return (
495
+ <>
496
+ {collapsed ? (
497
+ <div className="search-mobile">
498
+ {' '}
499
+ <div className="search-icon">
500
+ <svg viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" width="18" height="18">
501
+ <path
502
+ fill="#B3A6F4"
503
+ d="M962.048 907.776l-229.0176-229.0176a384.3072 384.3072 0 1 0-54.272 54.272l229.0176 229.0176a38.4 38.4 0 0 0 54.272-54.272zM436.1216 743.0656a306.944 306.944 0 1 1 306.944-306.944 307.3024 307.3024 0 0 1-306.944 306.944z"
504
+ ></path>
505
+ </svg>
506
+ </div>
507
+ </div>
508
+ ) : (
509
+ <div onMouseEnter={() => setIsHovered(true)} onMouseLeave={() => setIsHovered(false)}>
510
+ <div className="search">
511
+ <input id="menu-input" value={searchTerm} onChange={(e) => handleSearch(e.target.value)} className="search-input" placeholder="搜索菜单" />
512
+ <div className="search-icon">
513
+ <svg viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" width="18" height="18">
514
+ <path
515
+ fill={type === 'console' ? '#C2B7F6' : '#817F9B'}
516
+ d="M962.048 907.776l-229.0176-229.0176a384.3072 384.3072 0 1 0-54.272 54.272l229.0176 229.0176a38.4 38.4 0 0 0 54.272-54.272zM436.1216 743.0656a306.944 306.944 0 1 1 306.944-306.944 307.3024 307.3024 0 0 1-306.944 306.944z"
517
+ ></path>
518
+ </svg>
519
+ </div>
520
+ <div className="search-command">{navigator.platform.toLowerCase().includes('mac') ? '⌘' : '⊞'}K</div>
521
+ </div>
522
+ <div>
523
+ {isHovered && (
524
+ <>
525
+ {searchTerm ? (
526
+ <List split={false} className="list" size="small" bordered dataSource={searchResult} renderItem={(item) => <List.Item onClick={() => enter(item)}>{item.label}</List.Item>} />
527
+ ) : (
528
+ <List
529
+ split={false}
530
+ className="list"
531
+ header={<div>最近访问</div>}
532
+ size="small"
533
+ bordered
534
+ dataSource={searchHistory}
535
+ renderItem={(item) => {
536
+ return (
537
+ <div
538
+ className={'search-item'}
539
+ style={{
540
+ display: 'flex',
541
+ justifyContent: 'space-between',
542
+ alignItems: 'center',
543
+ }}
544
+ onClick={() => enter(item)}
545
+ >
546
+ <List.Item>{item.label}</List.Item>
547
+ <div
548
+ style={{ paddingRight: 10 }}
549
+ onClick={() => {
550
+ deleteHistory(item)
551
+ }}
552
+ >
553
+ <CloseCircleOutlined />
554
+ </div>
555
+ </div>
556
+ )
557
+ }}
558
+ />
559
+ )}
560
+ </>
561
+ )}
562
+ </div>
563
+ </div>
564
+ )}
565
+ </>
566
+ )
567
+ }
@@ -0,0 +1,169 @@
1
+ $header-height: 60px;
2
+ $base-color: #c6538c;
3
+
4
+ body {
5
+ overflow: hidden;
6
+ }
7
+
8
+ .layout-warp {
9
+ display: flex;
10
+ }
11
+
12
+ .ant-layout .ant-layout-sider {
13
+ background-image: linear-gradient(
14
+ -45deg,
15
+ rgba(103, 200, 21, 0.5),
16
+ rgba(55, 96, 244, 0.5),
17
+ rgba(245, 34, 45, 0.7)
18
+ );
19
+ background-position: center;
20
+ // background-color: #fff;
21
+ // background-color: #13c2c2;
22
+ background-color: #08979c;
23
+ // background-color: #531dab;
24
+ // background-color: #389e0d;
25
+
26
+ .ant-layout-sider-trigger {
27
+ background: transparent;
28
+ &:hover {
29
+ background: rgba(0, 0, 0, 0.12);
30
+ }
31
+ }
32
+ }
33
+
34
+ .layout-side {
35
+ height: 100vh;
36
+ user-select: none;
37
+ overflow: hidden;
38
+
39
+ .layout-logo {
40
+ cursor: pointer;
41
+ height: 60px;
42
+ margin: 8px auto;
43
+ display: flex;
44
+ justify-content: center;
45
+ align-items: center;
46
+ width: 100%;
47
+ z-index: 1;
48
+
49
+ .logo-img {
50
+ position: absolute;
51
+ height: 60px;
52
+ line-height: 60px;
53
+ object-fit: cover;
54
+ transition: all 0.8s cubic-bezier(0.645, 0.045, 0.355, 1);
55
+ }
56
+
57
+ .current-logo {
58
+ left: 0;
59
+ right: 0;
60
+ margin: auto;
61
+ }
62
+
63
+ .hide-logo {
64
+ left: -500px;
65
+ }
66
+ .hide-sub-logo {
67
+ right: -500px;
68
+ }
69
+ }
70
+
71
+ .layout-menu-container {
72
+ height: calc(100vh - 60px - 16px - 48px);
73
+ overflow: auto;
74
+ .ant-menu {
75
+ background: transparent !important;
76
+ }
77
+ .ant-menu-item-selected {
78
+ background: rgba(255, 255, 255, 0.3) !important;
79
+ }
80
+ }
81
+ }
82
+
83
+ .layout-header {
84
+ height: $header-height;
85
+ background: white;
86
+ z-index: 1;
87
+ position: relative;
88
+ display: flex;
89
+ justify-content: flex-start;
90
+ align-items: center;
91
+
92
+ .app-name {
93
+ margin-left: 24px;
94
+ font-weight: 500;
95
+ color: rgba(0, 0, 0, 0.65);
96
+ }
97
+
98
+ .layout-header-fill {
99
+ flex: 1;
100
+ }
101
+
102
+ .layout-header-actions {
103
+ display: flex;
104
+ justify-content: flex-start;
105
+ align-items: center;
106
+ height: 100%;
107
+ max-width: 400px;
108
+ z-index: 2;
109
+
110
+ .actions-item {
111
+ height: 36px;
112
+ border-radius: 6px;
113
+ transition: all 0.3s;
114
+ cursor: pointer;
115
+ margin: 0 4px;
116
+ padding: 0 4px;
117
+
118
+ display: flex;
119
+ justify-content: center;
120
+ align-items: center;
121
+
122
+ &:hover {
123
+ background: rgba(0, 0, 0, 0.06);
124
+ }
125
+ }
126
+ }
127
+
128
+ .layout-header-user {
129
+ height: 48px;
130
+ display: flex;
131
+ justify-content: flex-start;
132
+ align-items: center;
133
+ z-index: 2;
134
+ transition: all 0.3s;
135
+ padding: 4px 12px;
136
+ margin: 0 12px;
137
+ border-radius: 6px;
138
+ cursor: pointer;
139
+
140
+ &:hover {
141
+ background: rgba(0, 0, 0, 0.06);
142
+ }
143
+
144
+ .avatar {
145
+ width: 40px;
146
+ height: 40px;
147
+ border-radius: 50%;
148
+ margin-right: 12px;
149
+ }
150
+ }
151
+ }
152
+
153
+ .layout-main {
154
+ flex: 1;
155
+ height: 100%;
156
+ overflow: auto;
157
+ }
158
+
159
+ .layout-content {
160
+ width: 100%;
161
+ height: calc(100vh - #{$header-height});
162
+ overflow: auto;
163
+ }
164
+
165
+ .ant-menu-submenu-popup {
166
+ .ant-menu-item-selected {
167
+ background: rgba(255, 255, 255, 0.12) !important;
168
+ }
169
+ }