@zat-design/sisyphus-react 4.2.0 → 4.3.0-beta.10
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.
- package/dist/index.esm.css +1 -1
- package/dist/less.esm.css +1 -1
- package/es/ProEditTable/components/RenderField/index.js +1 -23
- package/es/ProEditTable/index.js +2 -6
- package/es/ProEditTable/propsType.d.ts +1 -3
- package/es/ProEditTable/style/index.less +0 -14
- package/es/ProEditTable/utils/index.js +0 -18
- package/es/ProForm/components/combination/Group/component/AddonWrapper/index.js +11 -2
- package/es/ProForm/components/combination/Group/style/index.less +42 -31
- package/es/ProForm/components/combination/Group/utils/index.d.ts +18 -18
- package/es/ProForm/utils/useForm.js +12 -10
- package/es/ProLayout/components/Layout/Menu/FoldMenu/index.js +11 -3
- package/es/ProLayout/components/Layout/Menu/OpenMenu/index.js +3 -3
- package/es/ProLayout/components/TabsManager/components/TabsHeader.d.ts +3 -5
- package/es/ProLayout/components/TabsManager/components/TabsHeader.js +65 -24
- package/es/ProLayout/components/TabsManager/hooks/useTabsState.js +59 -65
- package/es/ProLayout/components/TabsManager/index.js +68 -36
- package/es/ProLayout/components/TabsManager/propTypes.d.ts +8 -0
- package/es/ProLayout/components/TabsManager/style/index.less +60 -68
- package/es/ProLayout/components/TabsManager/utils/index.d.ts +14 -0
- package/es/ProLayout/components/TabsManager/utils/index.js +38 -6
- package/es/ProLayout/index.js +45 -15
- package/es/ProLayout/propTypes.d.ts +15 -0
- package/es/ProLayout/style/index.less +49 -1
- package/es/assets/edit.svg +1 -0
- package/package.json +1 -3
|
@@ -1,37 +1,29 @@
|
|
|
1
1
|
@import '../../../../style/variables.less'; // 引入变量
|
|
2
2
|
|
|
3
3
|
.pro-layout-tabs {
|
|
4
|
-
--pro-layout-tabs-primary: var(--ant-primary-color, #1677ff);
|
|
5
|
-
--pro-layout-tabs-active-bg: var(--ant-color-success, #00b578);
|
|
6
|
-
--pro-layout-tabs-text-color: var(--ant-color-text, #1f1f1f);
|
|
7
|
-
|
|
8
4
|
display: flex;
|
|
9
5
|
flex-direction: column;
|
|
10
6
|
height: 100%;
|
|
11
7
|
|
|
8
|
+
&-header-wrapper {
|
|
9
|
+
display: grid;
|
|
10
|
+
grid-template-rows: 0fr;
|
|
11
|
+
transition: grid-template-rows 0.3s cubic-bezier(0.4, 0, 0.2, 1);
|
|
12
|
+
|
|
13
|
+
&.tabs-visible {
|
|
14
|
+
grid-template-rows: 1fr;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
> .pro-layout-tabs-header {
|
|
18
|
+
overflow: hidden;
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
|
|
12
22
|
&-header {
|
|
13
23
|
align-items: center;
|
|
14
|
-
min-height: 48px;
|
|
15
|
-
padding: 12px 0;
|
|
16
24
|
border-bottom: none;
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
z-index: 90;
|
|
20
|
-
background: #fff;
|
|
21
|
-
box-shadow: none;
|
|
22
|
-
transition: box-shadow 0.3s ease;
|
|
23
|
-
|
|
24
|
-
&-shadow {
|
|
25
|
-
position: absolute;
|
|
26
|
-
left: 0;
|
|
27
|
-
right: 0;
|
|
28
|
-
bottom: 0;
|
|
29
|
-
height: 1px;
|
|
30
|
-
background: transparent;
|
|
31
|
-
pointer-events: none;
|
|
32
|
-
z-index: 1;
|
|
33
|
-
box-shadow: 1px 2px 4px 1px rgba(0, 55, 93, 0.2);
|
|
34
|
-
}
|
|
25
|
+
// 去掉 sticky 和白色背景:Tab 栏现在在 ProLayout 的渐变区域
|
|
26
|
+
background: transparent;
|
|
35
27
|
|
|
36
28
|
.pro-layout-tab-icon {
|
|
37
29
|
display: none !important;
|
|
@@ -43,7 +35,7 @@
|
|
|
43
35
|
.pro-layout-tab-list {
|
|
44
36
|
display: flex;
|
|
45
37
|
flex: 1;
|
|
46
|
-
gap:
|
|
38
|
+
gap: 8px;
|
|
47
39
|
|
|
48
40
|
&::-webkit-scrollbar {
|
|
49
41
|
height: 3px;
|
|
@@ -90,7 +82,6 @@
|
|
|
90
82
|
// 覆盖 nav 样式,使其匹配 pro-layout-tabs-header
|
|
91
83
|
.@{ant-prefix}-tabs-nav {
|
|
92
84
|
margin: 0;
|
|
93
|
-
// padding: 0 var(--zaui-space-size-md, 16px);
|
|
94
85
|
padding: 0;
|
|
95
86
|
border-bottom: none;
|
|
96
87
|
|
|
@@ -103,7 +94,7 @@
|
|
|
103
94
|
.@{ant-prefix}-tabs-nav-list {
|
|
104
95
|
display: flex;
|
|
105
96
|
flex: 1;
|
|
106
|
-
gap:
|
|
97
|
+
gap: 8px;
|
|
107
98
|
|
|
108
99
|
&::-webkit-scrollbar {
|
|
109
100
|
height: 3px;
|
|
@@ -129,7 +120,7 @@
|
|
|
129
120
|
display: flex;
|
|
130
121
|
flex-shrink: 0;
|
|
131
122
|
align-items: center;
|
|
132
|
-
|
|
123
|
+
height: 33px;
|
|
133
124
|
padding: 0 !important;
|
|
134
125
|
margin: 0 !important;
|
|
135
126
|
background: transparent !important;
|
|
@@ -151,7 +142,6 @@
|
|
|
151
142
|
.pro-layout-tab-item {
|
|
152
143
|
width: 100%;
|
|
153
144
|
height: 100%;
|
|
154
|
-
border: 1px solid rgb(217, 217, 217);
|
|
155
145
|
}
|
|
156
146
|
}
|
|
157
147
|
|
|
@@ -159,9 +149,6 @@
|
|
|
159
149
|
.@{ant-prefix}-tabs-tab-active {
|
|
160
150
|
background: transparent !important;
|
|
161
151
|
border: none !important;
|
|
162
|
-
.pro-layout-tab-item {
|
|
163
|
-
border-color: transparent !important;
|
|
164
|
-
}
|
|
165
152
|
|
|
166
153
|
&::before {
|
|
167
154
|
display: none;
|
|
@@ -175,40 +162,39 @@
|
|
|
175
162
|
}
|
|
176
163
|
}
|
|
177
164
|
|
|
165
|
+
.pro-layout-tabs-antd {
|
|
166
|
+
&.@{ant-prefix}-tabs {
|
|
167
|
+
.@{ant-prefix}-tabs-tab {
|
|
168
|
+
padding: 4px 0 5px !important;
|
|
169
|
+
margin-right: 8px !important;
|
|
170
|
+
margin-left: 0;
|
|
171
|
+
background: #e7e8ee;
|
|
172
|
+
transition: none;
|
|
173
|
+
&.@{ant-prefix}-tabs-tab-active {
|
|
174
|
+
background: #ffffff;
|
|
175
|
+
border-top: 2px solid var(--zaui-brand, #006aff);
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
.ant-tabs-nav {
|
|
179
|
+
margin-bottom: 0;
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
|
|
178
184
|
.pro-layout-tab-item {
|
|
179
185
|
position: relative;
|
|
180
186
|
display: flex;
|
|
181
187
|
flex-shrink: 0;
|
|
182
188
|
align-items: center;
|
|
183
|
-
min-height: 36px;
|
|
184
189
|
padding: 0;
|
|
185
|
-
background: #ffffff;
|
|
186
|
-
border: 1px solid transparent;
|
|
187
|
-
border-radius: 8px;
|
|
188
190
|
cursor: pointer;
|
|
189
|
-
transition: all 0.
|
|
191
|
+
transition: all 0.2s ease;
|
|
190
192
|
user-select: none;
|
|
191
193
|
|
|
192
|
-
&:hover {
|
|
193
|
-
background: #ffffff;
|
|
194
|
-
border-color: rgba(0, 0, 0, 0.06);
|
|
195
|
-
}
|
|
196
|
-
|
|
197
|
-
&.active {
|
|
198
|
-
z-index: 2;
|
|
199
|
-
background: var(--zaui-primary);
|
|
200
|
-
border-color: transparent;
|
|
201
|
-
|
|
202
|
-
&::before {
|
|
203
|
-
display: none;
|
|
204
|
-
}
|
|
205
|
-
}
|
|
206
|
-
|
|
207
194
|
.pro-layout-tab-content {
|
|
208
195
|
display: flex;
|
|
209
196
|
align-items: center;
|
|
210
|
-
|
|
211
|
-
padding: 6px 12px;
|
|
197
|
+
padding: 0 12px;
|
|
212
198
|
text-align: left;
|
|
213
199
|
|
|
214
200
|
.pro-layout-tab-icon {
|
|
@@ -232,12 +218,12 @@
|
|
|
232
218
|
.pro-layout-tab-title {
|
|
233
219
|
flex: 1;
|
|
234
220
|
overflow: hidden;
|
|
235
|
-
color: var(--
|
|
221
|
+
color: var(--zaui-text, #464646);
|
|
236
222
|
font-weight: 500;
|
|
237
223
|
font-size: 14px;
|
|
238
224
|
white-space: nowrap;
|
|
239
225
|
text-overflow: ellipsis;
|
|
240
|
-
transition: color 0.
|
|
226
|
+
transition: color 0.2s;
|
|
241
227
|
}
|
|
242
228
|
|
|
243
229
|
.pro-layout-tab-close {
|
|
@@ -245,38 +231,44 @@
|
|
|
245
231
|
flex-shrink: 0;
|
|
246
232
|
align-items: center;
|
|
247
233
|
justify-content: center;
|
|
248
|
-
margin-left:
|
|
249
|
-
padding:
|
|
250
|
-
color:
|
|
234
|
+
margin-left: 4px;
|
|
235
|
+
padding: 2px;
|
|
236
|
+
color: #333;
|
|
251
237
|
border-radius: 4px;
|
|
252
|
-
opacity:
|
|
253
|
-
transition: all 0.
|
|
238
|
+
opacity: 1;
|
|
239
|
+
transition: all 0.2s;
|
|
254
240
|
|
|
255
241
|
&:hover {
|
|
256
242
|
color: #ff4d4f;
|
|
257
|
-
background: rgba(255, 77, 79, 0.
|
|
258
|
-
opacity: 1;
|
|
243
|
+
background: rgba(255, 77, 79, 0.1);
|
|
259
244
|
}
|
|
260
245
|
}
|
|
261
246
|
}
|
|
262
247
|
|
|
248
|
+
// hover 时展示 close 按钮
|
|
249
|
+
&:hover .pro-layout-tab-close,
|
|
250
|
+
&.active .pro-layout-tab-close {
|
|
251
|
+
opacity: 1;
|
|
252
|
+
}
|
|
253
|
+
|
|
263
254
|
&.active .pro-layout-tab-content {
|
|
264
255
|
.pro-layout-tab-title {
|
|
265
|
-
color: #
|
|
256
|
+
color: var(--zaui-brand, #006aff);
|
|
266
257
|
font-weight: 600;
|
|
267
258
|
}
|
|
268
259
|
|
|
269
260
|
.pro-layout-tab-icon {
|
|
270
261
|
.iconfont {
|
|
271
|
-
color: #
|
|
262
|
+
color: var(--zaui-brand, #006aff);
|
|
272
263
|
}
|
|
273
264
|
}
|
|
274
265
|
|
|
275
266
|
.pro-layout-tab-close {
|
|
276
|
-
color: #
|
|
267
|
+
color: var(--zaui-brand, #006aff);
|
|
277
268
|
|
|
278
269
|
&:hover {
|
|
279
|
-
|
|
270
|
+
color: #ff4d4f;
|
|
271
|
+
background: rgba(255, 77, 79, 0.1);
|
|
280
272
|
}
|
|
281
273
|
}
|
|
282
274
|
}
|
|
@@ -298,7 +290,7 @@
|
|
|
298
290
|
@media (max-width: 768px) {
|
|
299
291
|
.pro-layout-tab-item {
|
|
300
292
|
.pro-layout-tab-content {
|
|
301
|
-
padding:
|
|
293
|
+
padding: 0 8px;
|
|
302
294
|
|
|
303
295
|
.pro-layout-tab-title {
|
|
304
296
|
max-width: 80px;
|
|
@@ -1,4 +1,9 @@
|
|
|
1
1
|
import { TabItem, MenusType } from '../../../propTypes';
|
|
2
|
+
/**
|
|
3
|
+
* 获取菜单实际用于路由/签页的路径
|
|
4
|
+
* 约定优先使用 redirectUrl,其次回退 url
|
|
5
|
+
*/
|
|
6
|
+
export declare const getMenuRoute: (menuItem: MenusType) => string;
|
|
2
7
|
/**
|
|
3
8
|
* 根据菜单项生成TabItem
|
|
4
9
|
*/
|
|
@@ -39,3 +44,12 @@ export declare const flattenMenuData: (menus?: MenusType[]) => MenusType[];
|
|
|
39
44
|
* 只有当菜单项没有子菜单或子菜单为空时,才认为是叶子节点
|
|
40
45
|
*/
|
|
41
46
|
export declare const isLeafMenuItem: (menuItem: MenusType) => boolean;
|
|
47
|
+
/**
|
|
48
|
+
* 判断菜单项是否为根节点
|
|
49
|
+
*/
|
|
50
|
+
export declare const isRootMenuItem: (menuItem: MenusType) => boolean;
|
|
51
|
+
/**
|
|
52
|
+
* 判断菜单项是否可以在 Tabs 模式下打开
|
|
53
|
+
* 规则:只有叶子节点(无 children)才可打开
|
|
54
|
+
*/
|
|
55
|
+
export declare const canOpenAsTab: (menuItem: MenusType) => boolean;
|
|
@@ -1,17 +1,27 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 获取菜单实际用于路由/签页的路径
|
|
3
|
+
* 约定优先使用 redirectUrl,其次回退 url
|
|
4
|
+
*/
|
|
5
|
+
export const getMenuRoute = menuItem => {
|
|
6
|
+
return menuItem.redirectUrl || menuItem.url || '';
|
|
7
|
+
};
|
|
8
|
+
|
|
1
9
|
/**
|
|
2
10
|
* 根据菜单项生成TabItem
|
|
3
11
|
*/
|
|
4
12
|
export const createTabFromMenu = (menuItem, index = 0) => {
|
|
5
|
-
|
|
13
|
+
const route = getMenuRoute(menuItem);
|
|
14
|
+
const result = {
|
|
6
15
|
id: String(menuItem.id || menuItem.code || menuItem.url || index),
|
|
7
16
|
code: menuItem.code,
|
|
8
17
|
name: menuItem.name,
|
|
9
18
|
title: menuItem.name,
|
|
10
|
-
url:
|
|
11
|
-
closable:
|
|
19
|
+
url: route,
|
|
20
|
+
closable: menuItem.closable !== false,
|
|
12
21
|
menuItem,
|
|
13
22
|
icon: menuItem.icon || menuItem.imgUrl
|
|
14
23
|
};
|
|
24
|
+
return result;
|
|
15
25
|
};
|
|
16
26
|
|
|
17
27
|
/**
|
|
@@ -34,16 +44,17 @@ export const generateTabId = (menuItem, existingIds) => {
|
|
|
34
44
|
* 检查菜单项是否应该外部跳转
|
|
35
45
|
*/
|
|
36
46
|
export const shouldOpenExternal = (menuItem, target) => {
|
|
37
|
-
|
|
47
|
+
const menuTarget = menuItem?.target || target;
|
|
48
|
+
return menuTarget === '_blank' || menuItem.type === 'EXTERNAL';
|
|
38
49
|
};
|
|
39
50
|
|
|
40
51
|
/**
|
|
41
52
|
* 处理外部跳转
|
|
42
53
|
*/
|
|
43
54
|
export const handleExternalOpen = menuItem => {
|
|
44
|
-
const url = menuItem
|
|
55
|
+
const url = getMenuRoute(menuItem);
|
|
45
56
|
if (url) {
|
|
46
|
-
window.open(url, '_blank');
|
|
57
|
+
window.open(url, menuItem.target || '_blank');
|
|
47
58
|
}
|
|
48
59
|
};
|
|
49
60
|
|
|
@@ -109,4 +120,25 @@ export const isLeafMenuItem = menuItem => {
|
|
|
109
120
|
} = menuItem || {};
|
|
110
121
|
// 如果 children 不存在、为 null、为 undefined,或者为空数组,则认为是叶子节点
|
|
111
122
|
return !children || Array.isArray(children) && children.length === 0;
|
|
123
|
+
};
|
|
124
|
+
|
|
125
|
+
/**
|
|
126
|
+
* 判断菜单项是否为根节点
|
|
127
|
+
*/
|
|
128
|
+
export const isRootMenuItem = menuItem => {
|
|
129
|
+
if (!menuItem) return false;
|
|
130
|
+
if (menuItem.parentId === null || menuItem.parentId === undefined) {
|
|
131
|
+
return true;
|
|
132
|
+
}
|
|
133
|
+
return Array.isArray(menuItem.keyIdPath) && menuItem.keyIdPath.length === 1;
|
|
134
|
+
};
|
|
135
|
+
|
|
136
|
+
/**
|
|
137
|
+
* 判断菜单项是否可以在 Tabs 模式下打开
|
|
138
|
+
* 规则:只有叶子节点(无 children)才可打开
|
|
139
|
+
*/
|
|
140
|
+
export const canOpenAsTab = menuItem => {
|
|
141
|
+
if (!menuItem) return false;
|
|
142
|
+
if (!(menuItem.url || menuItem.redirectUrl)) return false;
|
|
143
|
+
return isLeafMenuItem(menuItem);
|
|
112
144
|
};
|
package/es/ProLayout/index.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/* eslint-disable func-call-spacing */
|
|
2
2
|
/* eslint-disable no-spaced-func */
|
|
3
|
-
import { createContext, useMemo, useRef, useCallback } from 'react';
|
|
3
|
+
import { createContext, useMemo, useRef, useCallback, useState } from 'react';
|
|
4
4
|
import classNames from 'classnames';
|
|
5
5
|
import { useSetState, useToggle, useDeepCompareEffect } from 'ahooks';
|
|
6
6
|
import { ProWaterMark } from "../index";
|
|
@@ -11,7 +11,7 @@ import { isTabsMode, validateTabsProps } from "./propTypes";
|
|
|
11
11
|
import { useProLayoutTabs } from "./components/TabsManager/hooks/useProLayoutTabs";
|
|
12
12
|
import { useActiveTab } from "./components/TabsManager/hooks/useActiveTab";
|
|
13
13
|
import { transformMenus } from "./utils";
|
|
14
|
-
import {
|
|
14
|
+
import { canOpenAsTab } from "./components/TabsManager/utils";
|
|
15
15
|
import headerBg from "../assets/header_bg.png";
|
|
16
16
|
|
|
17
17
|
// 全局上下文
|
|
@@ -51,6 +51,10 @@ const ProLayout = props => {
|
|
|
51
51
|
const isTabsLayout = isTabsMode(props);
|
|
52
52
|
validateTabsProps(mode, tabs);
|
|
53
53
|
const tabsManagerRef = useRef(null);
|
|
54
|
+
|
|
55
|
+
// Tab 栏 Portal 挂载目标及动画状态
|
|
56
|
+
const [tabsBarEl, setTabsBarEl] = useState(null);
|
|
57
|
+
const [hasTabs, setHasTabs] = useState(false);
|
|
54
58
|
const [{
|
|
55
59
|
notice,
|
|
56
60
|
menus,
|
|
@@ -78,9 +82,22 @@ const ProLayout = props => {
|
|
|
78
82
|
menus: menuData
|
|
79
83
|
});
|
|
80
84
|
}, [dataSource]);
|
|
81
|
-
const menuDataSource = useMemo(() =>
|
|
82
|
-
menus
|
|
83
|
-
|
|
85
|
+
const menuDataSource = useMemo(() => {
|
|
86
|
+
// menus 已通过 useDeepCompareEffect 填充,直接使用
|
|
87
|
+
if (Array.isArray(menus) && menus.length > 0) {
|
|
88
|
+
return {
|
|
89
|
+
menus
|
|
90
|
+
};
|
|
91
|
+
}
|
|
92
|
+
// menus state 尚未填充(初始为 []),直接用 dataSource 原始 menus,
|
|
93
|
+
// 确保 tabsInstance 第一次创建时就能查到完整菜单数据(含 closable 等属性)
|
|
94
|
+
if (!Array.isArray(dataSource) && Array.isArray(dataSource?.menus)) {
|
|
95
|
+
return dataSource;
|
|
96
|
+
}
|
|
97
|
+
return {
|
|
98
|
+
menus: menus || []
|
|
99
|
+
};
|
|
100
|
+
}, [menus, dataSource]);
|
|
84
101
|
const enhancedTabsConfig = useMemo(() => {
|
|
85
102
|
if (!isTabsLayout || !tabs) {
|
|
86
103
|
return tabs;
|
|
@@ -95,7 +112,7 @@ const ProLayout = props => {
|
|
|
95
112
|
});
|
|
96
113
|
return;
|
|
97
114
|
}
|
|
98
|
-
const targetPath = activeTab?.url || activeTab?.menuItem?.router || activeTab?.menuItem?.
|
|
115
|
+
const targetPath = activeTab?.url || activeTab?.menuItem?.router || activeTab?.menuItem?.redirectUrl || activeTab?.menuItem?.url;
|
|
99
116
|
if (targetPath && targetPath !== selectedPath) {
|
|
100
117
|
setState({
|
|
101
118
|
selectedPath: targetPath
|
|
@@ -116,6 +133,8 @@ const ProLayout = props => {
|
|
|
116
133
|
config: enhancedTabsConfig,
|
|
117
134
|
dataSource: menuDataSource,
|
|
118
135
|
originalOnMenuClick: onMenuClick,
|
|
136
|
+
tabsBarContainer: tabsBarEl,
|
|
137
|
+
onTabsChange: setHasTabs,
|
|
119
138
|
children: children
|
|
120
139
|
});
|
|
121
140
|
};
|
|
@@ -128,13 +147,16 @@ const ProLayout = props => {
|
|
|
128
147
|
|
|
129
148
|
// tabs 模式:调用 TabsManager 的 handleMenuClick 来添加标签页
|
|
130
149
|
tabsManagerRef.current?.handleMenuClick?.(params);
|
|
131
|
-
|
|
132
|
-
// 非叶子节点,直接允许激活
|
|
133
|
-
if (!params.item || !isLeafMenuItem(params.item)) {
|
|
150
|
+
if (!params.item) {
|
|
134
151
|
return true;
|
|
135
152
|
}
|
|
136
153
|
|
|
137
|
-
//
|
|
154
|
+
// 只有叶子节点(无 children)可入签;有 children 的节点不激活
|
|
155
|
+
if (!canOpenAsTab(params.item)) {
|
|
156
|
+
return false;
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
// 可入签节点:检查是否可以添加标签页(检查 max 限制、_blank 等)
|
|
138
160
|
const canAdd = tabsManagerRef.current?.canAddTab?.(params.item);
|
|
139
161
|
if (!canAdd) {
|
|
140
162
|
// 超过限制,返回 false 阻止菜单激活
|
|
@@ -142,13 +164,14 @@ const ProLayout = props => {
|
|
|
142
164
|
}
|
|
143
165
|
|
|
144
166
|
// 可以添加标签页,设置选中路径(激活菜单)
|
|
145
|
-
const targetPath = params.item?.
|
|
167
|
+
const targetPath = params.item?.redirectUrl || params.item?.url || params.item?.router;
|
|
146
168
|
if (targetPath && targetPath !== selectedPath) {
|
|
147
169
|
setState({
|
|
148
170
|
selectedPath: targetPath
|
|
149
171
|
});
|
|
150
172
|
}
|
|
151
|
-
|
|
173
|
+
// tabs 模式下由 Tab 管理内容,阻止菜单默认 Link 跳转
|
|
174
|
+
return false;
|
|
152
175
|
}, [isTabsLayout, onMenuClick, selectedPath]);
|
|
153
176
|
|
|
154
177
|
/**
|
|
@@ -214,21 +237,28 @@ const ProLayout = props => {
|
|
|
214
237
|
[`${className}`]: className
|
|
215
238
|
}),
|
|
216
239
|
style: {
|
|
217
|
-
'--header-bg-image': `url(${headerBg})
|
|
240
|
+
'--header-bg-image': `url(${headerBg})`,
|
|
241
|
+
'--pro-layout-header-height': `${headerHeight}px`
|
|
218
242
|
},
|
|
219
243
|
children: [/*#__PURE__*/_jsx(Header, {
|
|
220
244
|
...headerProps
|
|
221
245
|
}), /*#__PURE__*/_jsx(Notice, {
|
|
222
246
|
...noticeProps
|
|
247
|
+
}), /*#__PURE__*/_jsx("div", {
|
|
248
|
+
ref: setTabsBarEl,
|
|
249
|
+
className: `pro-layout-tabs-bar-wrapper${hasTabs ? ' tabs-visible' : ''}${collapsed ? ' tabs-menu-open' : ''}`,
|
|
250
|
+
style: {
|
|
251
|
+
marginTop: headerHeight + noticeHeight
|
|
252
|
+
}
|
|
223
253
|
}), /*#__PURE__*/_jsxs("div", {
|
|
224
254
|
className: contentCls,
|
|
225
255
|
children: [/*#__PURE__*/_jsx(Menu, {
|
|
226
256
|
...menuProps
|
|
227
257
|
}), /*#__PURE__*/_jsx("div", {
|
|
228
|
-
className:
|
|
258
|
+
className: `pro-layout-content${hasTabs ? ' pro-layout-content-has-tabs' : ''}`,
|
|
229
259
|
style: {
|
|
230
260
|
...contentStyle,
|
|
231
|
-
marginTop:
|
|
261
|
+
marginTop: 0
|
|
232
262
|
},
|
|
233
263
|
children: renderContent()
|
|
234
264
|
})]
|
|
@@ -124,6 +124,11 @@ export interface MenusType {
|
|
|
124
124
|
* @default -
|
|
125
125
|
*/
|
|
126
126
|
type?: string;
|
|
127
|
+
/**
|
|
128
|
+
* @description 当前菜单点击后的打开方式
|
|
129
|
+
* @default "_self"
|
|
130
|
+
*/
|
|
131
|
+
target?: '_blank' | '_parent' | '_self' | '_top';
|
|
127
132
|
/**
|
|
128
133
|
* @description 允许扩展字段
|
|
129
134
|
*/
|
|
@@ -399,6 +404,11 @@ export interface TabsConfig {
|
|
|
399
404
|
storage?: TabsStorageStrategy;
|
|
400
405
|
cacheKey?: string;
|
|
401
406
|
onTabChange?: (activeKey: string, activeTab: TabItem | undefined, allTabs: TabItem[]) => void;
|
|
407
|
+
/**
|
|
408
|
+
* @description 是否允许标签页拖拽排序
|
|
409
|
+
* @default true
|
|
410
|
+
*/
|
|
411
|
+
draggable?: boolean;
|
|
402
412
|
/**
|
|
403
413
|
* @description 激活组件解析函数,根据 component 标识返回对应的 React 组件
|
|
404
414
|
*/
|
|
@@ -419,6 +429,11 @@ export interface TabsConfig {
|
|
|
419
429
|
tab: TabItem;
|
|
420
430
|
tabs: TabItem[];
|
|
421
431
|
}) => void;
|
|
432
|
+
/**
|
|
433
|
+
* @description 声明式固定标签页,传入菜单 code 数组,这些 tab 会在初始化时自动添加且不可关闭
|
|
434
|
+
* @example fixed: ['Workspace', 'PolicyInput']
|
|
435
|
+
*/
|
|
436
|
+
fixed?: string[];
|
|
422
437
|
}
|
|
423
438
|
export type ProLayoutMode = 'normal' | 'tabs';
|
|
424
439
|
export interface ProLayoutTabsProps extends ProLayoutBaseProps {
|
|
@@ -287,12 +287,52 @@
|
|
|
287
287
|
}
|
|
288
288
|
}
|
|
289
289
|
|
|
290
|
+
/** Tab 栏 Portal 挂载点(位于 header 渐变区,内容区之上) */
|
|
291
|
+
.pro-layout-tabs-bar-wrapper {
|
|
292
|
+
// 与 pro-layout-content 对齐:同样的左右边距,无内边距让 tab 从左侧直接对齐
|
|
293
|
+
margin-right: var(--zaui-space-size-md, 16px);
|
|
294
|
+
margin-left: 48px;
|
|
295
|
+
padding: 0;
|
|
296
|
+
// 滚动时固定在 header 正下方
|
|
297
|
+
position: sticky;
|
|
298
|
+
top: var(--pro-layout-header-height, 64px);
|
|
299
|
+
z-index: 89;
|
|
300
|
+
// 与 ::before 渐变层像素级对齐:滚动时遮住上滚的白色内容,同时保持渐变背景可见
|
|
301
|
+
// background-color 作为实体打底,防止渐变图片浅色区域透出白色内容
|
|
302
|
+
background-color: #f7f9fd;
|
|
303
|
+
background-image: var(--header-bg-image);
|
|
304
|
+
background-repeat: no-repeat;
|
|
305
|
+
background-position: top center;
|
|
306
|
+
background-size: 100% auto;
|
|
307
|
+
background-attachment: fixed;
|
|
308
|
+
// 高度动画:CSS Grid 技巧,支持不定高度平滑过渡
|
|
309
|
+
display: grid;
|
|
310
|
+
grid-template-rows: 0fr;
|
|
311
|
+
transition: margin-left 0.3s cubic-bezier(0.2, 0, 0, 1), grid-template-rows 0.3s cubic-bezier(0.4, 0, 0.2, 1);
|
|
312
|
+
|
|
313
|
+
// 菜单展开时与内容区同步右移
|
|
314
|
+
&.tabs-menu-open {
|
|
315
|
+
margin-left: 220px;
|
|
316
|
+
}
|
|
317
|
+
|
|
318
|
+
// Tab 存在时展开
|
|
319
|
+
&.tabs-visible {
|
|
320
|
+
grid-template-rows: 1fr;
|
|
321
|
+
}
|
|
322
|
+
|
|
323
|
+
// Grid 子元素需要 overflow: hidden 才能实现 0fr 收起
|
|
324
|
+
> * {
|
|
325
|
+
overflow: hidden;
|
|
326
|
+
min-height: 0;
|
|
327
|
+
}
|
|
328
|
+
}
|
|
329
|
+
|
|
290
330
|
/** 内容区 */
|
|
291
331
|
.pro-layout-content {
|
|
292
332
|
position: relative;
|
|
293
333
|
z-index: 10;
|
|
294
334
|
flex: 1;
|
|
295
|
-
margin-top:
|
|
335
|
+
margin-top: 0;
|
|
296
336
|
margin-right: var(--zaui-space-size-md, 16px);
|
|
297
337
|
margin-bottom: 0;
|
|
298
338
|
margin-left: 48px;
|
|
@@ -304,6 +344,14 @@
|
|
|
304
344
|
border-bottom: none;
|
|
305
345
|
border-radius: var(--zaui-border-radius, 8px) var(--zaui-border-radius, 8px) 0 0;
|
|
306
346
|
transition: all 0.24s ease;
|
|
347
|
+
|
|
348
|
+
// Tab 存在时:顶部边框透明(不用 none,避免 transition:all 产生黑色闪烁)、移除顶部圆角,与 Tab 栏无缝衔接;补上顶部 padding
|
|
349
|
+
&-has-tabs {
|
|
350
|
+
border-top-color: transparent;
|
|
351
|
+
border-radius: 0;
|
|
352
|
+
padding-top: var(--zaui-space-size-md, 16px);
|
|
353
|
+
border-top-right-radius: var(--zaui-border-radius, 8px);
|
|
354
|
+
}
|
|
307
355
|
}
|
|
308
356
|
|
|
309
357
|
// 纯净模式:隐藏背景图
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1775025459029" class="icon" viewBox="0 0 1025 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="7119" xmlns:xlink="http://www.w3.org/1999/xlink" width="200.1953125" height="200"><path d="M181.10185262 930.4882664c-18.69801175 0-33.42977859-15.29837325-33.42977858-33.42977858 0-18.69801175 15.29837325-33.42977859 33.42977858-33.4297786h691.25982844c18.69801175 0 33.42977859 15.29837325 33.42977859 33.4297786 0 18.69801175-15.29837325 33.42977859-33.42977859 33.42977858h-691.25982844z m671.42860384-747.92047012L752.80772713 82.84506694c-12.46534117-12.46534117-32.86317217-12.46534117-45.32851335 0l-100.85594218 100.85594218 145.05124269 145.05124269 100.85594217-100.85594218c12.46534117-12.46534117 12.46534117-32.29656575 0-45.32851335z m-275.93732495 31.16335293L240.59552637 549.72875434c-9.06570266 9.06570266-16.9981925 28.89692726-16.9981925 28.89692726l-52.12779033 165.44907369c-3.96624492 12.46534117 7.93248983 23.7974695 20.397831 20.397831l164.31586085-52.12779034s19.83122459-7.36588342 29.46353368-17.56479891L721.6443742 358.7823919 576.59313151 213.73114921z" fill="#2C2C2C" p-id="7120"></path></svg>
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@zat-design/sisyphus-react",
|
|
3
|
-
"version": "4.
|
|
3
|
+
"version": "4.3.0-beta.10",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"files": [
|
|
6
6
|
"es",
|
|
@@ -94,7 +94,6 @@
|
|
|
94
94
|
"react-resizable": {
|
|
95
95
|
"react-draggable": "<4.5.0"
|
|
96
96
|
},
|
|
97
|
-
"@ant-design/icons": "^6.1.0",
|
|
98
97
|
"@babel/core": "^7.26.0",
|
|
99
98
|
"react-docgen-typescript-dumi-tmp": {
|
|
100
99
|
"typescript": "^4.9.5"
|
|
@@ -104,7 +103,6 @@
|
|
|
104
103
|
},
|
|
105
104
|
"resolutions": {
|
|
106
105
|
"react-resizable/react-draggable": "<4.5.0",
|
|
107
|
-
"@ant-design/icons": "^6.1.0",
|
|
108
106
|
"@babel/core": "^7.26.0",
|
|
109
107
|
"react-docgen-typescript-dumi-tmp/typescript": "^4.9.5",
|
|
110
108
|
"esbuild": "0.21.4",
|