@zat-design/sisyphus-react 4.5.10-beta.1 → 4.6.0-beta.1
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/es/FormsProvider/index.js +14 -21
- package/es/ProAction/components/CheckModalContent/index.js +12 -26
- package/es/ProAction/index.js +79 -83
- package/es/ProAction/propsType.js +0 -1
- package/es/ProConfigProvider/index.js +63 -110
- package/es/ProConfigProvider/propsType.js +0 -1
- package/es/ProDownload/index.js +55 -65
- package/es/ProDownload/propsType.js +0 -1
- package/es/ProDownload/utils.js +61 -95
- package/es/ProDrawerForm/components/ProDrawer/index.js +83 -113
- package/es/ProDrawerForm/components/ProModal/index.js +77 -108
- package/es/ProDrawerForm/components/index.js +6 -2
- package/es/ProDrawerForm/hooks/useConfirmClose.js +20 -39
- package/es/ProDrawerForm/index.js +29 -38
- package/es/ProDrawerForm/propsType.js +0 -1
- package/es/ProDrawerForm/utils/index.js +18 -36
- package/es/ProEditLabel/components/RenderProForm.js +45 -49
- package/es/ProEditLabel/index.js +126 -163
- package/es/ProEditLabel/propsType.js +0 -1
- package/es/ProEditLabel/utils/index.js +5 -8
- package/es/ProEditTable/components/ActionButton/index.js +111 -119
- package/es/ProEditTable/components/RcTable/BaseTable.js +38 -51
- package/es/ProEditTable/components/RcTable/DraggableTable.js +97 -129
- package/es/ProEditTable/components/RcTable/index.js +6 -4
- package/es/ProEditTable/components/RenderField/ListChangedWrapper.js +77 -95
- package/es/ProEditTable/components/RenderField/index.js +490 -587
- package/es/ProEditTable/components/RenderField/propsType.js +0 -1
- package/es/ProEditTable/components/RenderField/tools.js +115 -112
- package/es/ProEditTable/components/RenderToolbar/index.js +47 -73
- package/es/ProEditTable/components/Summary/index.js +38 -64
- package/es/ProEditTable/components/Validator/index.js +46 -46
- package/es/ProEditTable/components/index.js +12 -5
- package/es/ProEditTable/index.js +456 -378
- package/es/ProEditTable/propsType.js +0 -1
- package/es/ProEditTable/utils/config.js +60 -122
- package/es/ProEditTable/utils/diffOriginal.js +45 -82
- package/es/ProEditTable/utils/getDefaultProps.js +19 -24
- package/es/ProEditTable/utils/index.js +150 -236
- package/es/ProEditTable/utils/tools.js +149 -286
- package/es/ProEditTable/utils/transform.js +25 -30
- package/es/ProEditTable/utils/useEditTableError.js +30 -43
- package/es/ProEditTable/utils/useShouldUpdateForTable.js +42 -72
- package/es/ProEditTable/utils/validateAll.js +87 -154
- package/es/ProEnum/components/Group.js +38 -30
- package/es/ProEnum/components/Tag.js +22 -26
- package/es/ProEnum/hooks/useEnum.js +48 -116
- package/es/ProEnum/hooks/useEnumRequest.js +128 -179
- package/es/ProEnum/hooks/useFrequentEnumRequest.js +40 -48
- package/es/ProEnum/index.js +162 -172
- package/es/ProEnum/propsType.js +0 -1
- package/es/ProEnum/utils/eventCenter.js +10 -12
- package/es/ProEnum/utils/frequentEnum.js +35 -92
- package/es/ProEnum/utils/getEnum.js +32 -90
- package/es/ProEnum/utils/getEnumLabel.js +44 -49
- package/es/ProEnum/utils/index.js +93 -207
- package/es/ProForm/components/Container.js +13 -28
- package/es/ProForm/components/FormFooter/index.js +36 -44
- package/es/ProForm/components/FormFooter/propsType.js +0 -1
- package/es/ProForm/components/base/Checkbox/index.js +32 -59
- package/es/ProForm/components/base/DatePicker/index.js +49 -71
- package/es/ProForm/components/base/Input/index.js +63 -97
- package/es/ProForm/components/base/Input/propsType.js +0 -1
- package/es/ProForm/components/base/InputNumber/index.js +118 -172
- package/es/ProForm/components/base/Radio/index.js +39 -52
- package/es/ProForm/components/base/RangePicker/index.js +109 -127
- package/es/ProForm/components/base/RangePicker/useDateRange.js +20 -17
- package/es/ProForm/components/base/Select/index.js +63 -89
- package/es/ProForm/components/base/Switch/index.js +27 -35
- package/es/ProForm/components/base/SwitchCheckbox/index.js +36 -54
- package/es/ProForm/components/base/TextArea/index.js +30 -41
- package/es/ProForm/components/base/TimePicker/index.js +27 -37
- package/es/ProForm/components/combination/Container/index.js +37 -47
- package/es/ProForm/components/combination/Container/propsType.js +0 -1
- package/es/ProForm/components/combination/FormList/components/ActionButton.js +165 -237
- package/es/ProForm/components/combination/FormList/components/BlockFields.js +98 -103
- package/es/ProForm/components/combination/FormList/components/Empty.js +27 -54
- package/es/ProForm/components/combination/FormList/components/LineFields.js +57 -54
- package/es/ProForm/components/combination/FormList/components/ToolbarButton.js +61 -109
- package/es/ProForm/components/combination/FormList/index.js +151 -161
- package/es/ProForm/components/combination/FormList/propsType.js +0 -1
- package/es/ProForm/components/combination/FormList/utils.js +22 -38
- package/es/ProForm/components/combination/Group/component/AddonWrapper/index.js +12 -28
- package/es/ProForm/components/combination/Group/component/ComRender.js +50 -111
- package/es/ProForm/components/combination/Group/component/FlexibleGroup.js +105 -206
- package/es/ProForm/components/combination/Group/hooks/index.js +68 -128
- package/es/ProForm/components/combination/Group/index.js +87 -126
- package/es/ProForm/components/combination/Group/propsType.js +0 -1
- package/es/ProForm/components/combination/Group/utils/index.js +124 -239
- package/es/ProForm/components/combination/ProCascader/index.js +156 -199
- package/es/ProForm/components/combination/ProCascader/propsType.js +0 -1
- package/es/ProForm/components/combination/ProCascader/utils/index.js +12 -21
- package/es/ProForm/components/combination/ProModalSelect/hooks/useRequestList.js +63 -75
- package/es/ProForm/components/combination/ProModalSelect/index.js +290 -348
- package/es/ProForm/components/combination/ProModalSelect/propsType.js +0 -1
- package/es/ProForm/components/combination/ProModalSelect/utils/index.js +32 -39
- package/es/ProForm/components/combination/ProNumberRange/index.js +100 -156
- package/es/ProForm/components/combination/ProNumberRange/propsType.js +0 -1
- package/es/ProForm/components/combination/ProRangeLimit/index.js +104 -115
- package/es/ProForm/components/combination/ProRangeLimit/propsType.js +0 -1
- package/es/ProForm/components/combination/ProTimeLimit/hooks/useControlled.js +16 -16
- package/es/ProForm/components/combination/ProTimeLimit/index.js +75 -109
- package/es/ProForm/components/index.js +56 -34
- package/es/ProForm/components/render/ChangedWrapper.js +85 -94
- package/es/ProForm/components/render/ConfirmWrapper.js +27 -39
- package/es/ProForm/components/render/CustomComponentViewWrapper.js +65 -82
- package/es/ProForm/components/render/Render.js +223 -329
- package/es/ProForm/components/render/RenderFields.js +76 -113
- package/es/ProForm/components/render/propsType.js +0 -1
- package/es/ProForm/hooks/useControlled.js +8 -10
- package/es/ProForm/hooks/useDeepCompareMemo.js +11 -11
- package/es/ProForm/hooks/useFieldProps.js +8 -4
- package/es/ProForm/hooks/useForm.js +50 -110
- package/es/ProForm/hooks/useRules.js +17 -33
- package/es/ProForm/hooks/useShouldUpdate.js +77 -152
- package/es/ProForm/hooks/useWatch.js +58 -129
- package/es/ProForm/index.js +157 -194
- package/es/ProForm/propsType.js +15 -7
- package/es/ProForm/utils/buildFormItemProps.js +51 -58
- package/es/ProForm/utils/diffOriginal.js +43 -73
- package/es/ProForm/utils/getDefaultProps.js +18 -24
- package/es/ProForm/utils/index.js +159 -234
- package/es/ProForm/utils/processDependencies.js +21 -60
- package/es/ProForm/utils/reactiveValues.js +20 -34
- package/es/ProForm/utils/rulesCreator.js +42 -40
- package/es/ProForm/utils/transformNames.js +10 -13
- package/es/ProForm/utils/transformValue.js +16 -29
- package/es/ProForm/utils/valueType.js +96 -178
- package/es/ProIcon/config/index.js +340 -274
- package/es/ProIcon/index.js +135 -209
- package/es/ProIcon/propsTypes.js +0 -1
- package/es/ProIcon/utils/index.js +24 -39
- package/es/ProLayout/components/Layout/Header/index.js +108 -141
- package/es/ProLayout/components/Layout/Menu/FoldMenu/index.js +134 -190
- package/es/ProLayout/components/Layout/Menu/OpenMenu/index.js +111 -137
- package/es/ProLayout/components/Layout/Menu/OpenMenu/propsType.js +0 -1
- package/es/ProLayout/components/Layout/Menu/SideMenu/index.js +23 -31
- package/es/ProLayout/components/Layout/Menu/index.js +92 -89
- package/es/ProLayout/components/Layout/Notice/index.js +13 -27
- package/es/ProLayout/components/Layout/index.js +8 -3
- package/es/ProLayout/components/ProCollapse/PropTypes.js +0 -1
- package/es/ProLayout/components/ProCollapse/index.js +89 -111
- package/es/ProLayout/components/ProFooter/PropTypes.js +0 -1
- package/es/ProLayout/components/ProFooter/index.js +27 -25
- package/es/ProLayout/components/ProHeader/PropTypes.js +0 -1
- package/es/ProLayout/components/ProHeader/components/Copy/index.js +23 -21
- package/es/ProLayout/components/ProHeader/components/Describe/index.js +67 -86
- package/es/ProLayout/components/ProHeader/components/ProBackBtn/index.js +18 -21
- package/es/ProLayout/components/ProHeader/components/ProBackBtn/propsType.js +0 -1
- package/es/ProLayout/components/ProHeader/components/index.js +6 -2
- package/es/ProLayout/components/ProHeader/index.js +216 -356
- package/es/ProLayout/components/ProHeader/utils/index.js +19 -26
- package/es/ProLayout/components/TabsManager/components/TabContextMenu.js +92 -85
- package/es/ProLayout/components/TabsManager/components/TabItem.js +53 -64
- package/es/ProLayout/components/TabsManager/components/TabsContext.js +5 -5
- package/es/ProLayout/components/TabsManager/components/TabsHeader.js +42 -52
- package/es/ProLayout/components/TabsManager/hooks/useActiveTab.js +8 -9
- package/es/ProLayout/components/TabsManager/hooks/useIframeRoute.js +19 -32
- package/es/ProLayout/components/TabsManager/hooks/useProLayoutTabs.js +6 -20
- package/es/ProLayout/components/TabsManager/hooks/useTabsCache.js +25 -42
- package/es/ProLayout/components/TabsManager/hooks/useTabsState.js +310 -412
- package/es/ProLayout/components/TabsManager/hooks/useTabsUrlSync.js +132 -95
- package/es/ProLayout/components/TabsManager/index.js +415 -391
- package/es/ProLayout/components/TabsManager/propTypes.js +7 -15
- package/es/ProLayout/components/TabsManager/utils/historyObserver.js +26 -23
- package/es/ProLayout/components/TabsManager/utils/index.d.ts +2 -1
- package/es/ProLayout/components/TabsManager/utils/index.js +135 -184
- package/es/ProLayout/components/index.js +8 -3
- package/es/ProLayout/index.js +171 -229
- package/es/ProLayout/propTypes.d.ts +9 -0
- package/es/ProLayout/propTypes.js +12 -52
- package/es/ProLayout/utils/index.js +48 -128
- package/es/ProSelect/components/AdaptiveTooltip.js +26 -25
- package/es/ProSelect/index.js +184 -229
- package/es/ProSelect/propsType.js +0 -1
- package/es/ProSelect/utils/index.js +100 -146
- package/es/ProStep/components/Anchor/index.js +71 -82
- package/es/ProStep/components/Item/index.js +49 -56
- package/es/ProStep/components/LazyLoad/index.js +23 -29
- package/es/ProStep/components/Listener/index.js +20 -33
- package/es/ProStep/components/Step/index.js +31 -38
- package/es/ProStep/constants.js +4 -1
- package/es/ProStep/index.js +166 -153
- package/es/ProStep/propsType.js +0 -1
- package/es/ProStep/utils/index.js +29 -55
- package/es/ProStepTab/index.js +83 -138
- package/es/ProStepTab/propsType.js +0 -1
- package/es/ProTable/components/EditableCell/EditIcon.js +10 -14
- package/es/ProTable/components/EditableCell/index.js +37 -71
- package/es/ProTable/components/EditableCell/propsType.js +0 -1
- package/es/ProTable/components/FormatColumn/index.js +209 -340
- package/es/ProTable/components/FormatColumn/propsType.js +0 -1
- package/es/ProTable/components/RcTable/components/BaseTable/index.js +35 -39
- package/es/ProTable/components/RcTable/components/DraggableTable/components/DndWrapper/index.js +80 -107
- package/es/ProTable/components/RcTable/components/DraggableTable/components/DndWrapper/utils/index.js +54 -48
- package/es/ProTable/components/RcTable/components/DraggableTable/components/DndWrapper/utils/propsType.js +0 -1
- package/es/ProTable/components/RcTable/components/DraggableTable/index.js +47 -54
- package/es/ProTable/components/RcTable/index.js +6 -4
- package/es/ProTable/components/RenderColumn/index.js +158 -186
- package/es/ProTable/components/RenderEmptyText/index.js +12 -21
- package/es/ProTable/components/RenderFooter/index.js +15 -15
- package/es/ProTable/components/RenderSummary/index.js +33 -50
- package/es/ProTable/components/RenderTableHeader/index.js +44 -46
- package/es/ProTable/components/RenderTabs/index.js +47 -51
- package/es/ProTable/components/TableResizable/index.js +56 -72
- package/es/ProTable/components/TooltipTitle/index.js +13 -21
- package/es/ProTable/components/index.js +16 -36
- package/es/ProTable/hooks/useAntdTable.js +185 -219
- package/es/ProTable/index.js +232 -249
- package/es/ProTable/propsType.js +0 -1
- package/es/ProTable/utils/columnStorage.js +63 -88
- package/es/ProTable/utils/index.js +57 -90
- package/es/ProTabs/components/Card/index.js +20 -48
- package/es/ProTabs/components/index.js +4 -1
- package/es/ProTabs/index.js +39 -56
- package/es/ProTabs/propType.js +0 -1
- package/es/ProThemeTools/component/ProTools/index.js +106 -158
- package/es/ProThemeTools/component/index.js +4 -1
- package/es/ProThemeTools/context/ThemeContext.js +67 -146
- package/es/ProThemeTools/index.js +103 -156
- package/es/ProThemeTools/propsType.js +0 -1
- package/es/ProThemeTools/utils/index.js +60 -109
- package/es/ProTooltip/index.js +132 -165
- package/es/ProTooltip/propsType.js +0 -1
- package/es/ProTree/components/AdaptiveTooltip.js +15 -17
- package/es/ProTree/components/CloseIcon.js +18 -26
- package/es/ProTree/components/List.js +28 -47
- package/es/ProTree/components/ProTree.js +152 -211
- package/es/ProTree/components/ProTreeSelect/index.js +254 -458
- package/es/ProTree/components/ProTreeSelect/propsType.js +0 -1
- package/es/ProTree/components/SearchTitle.js +23 -42
- package/es/ProTree/components/Tree.js +147 -195
- package/es/ProTree/components/index.js +10 -5
- package/es/ProTree/index.js +12 -16
- package/es/ProTree/propsType.js +0 -1
- package/es/ProTree/utils.js +46 -118
- package/es/ProTreeModal/components/Cascader.js +56 -64
- package/es/ProTreeModal/components/CloseIcon.js +18 -26
- package/es/ProTreeModal/components/List.js +114 -180
- package/es/ProTreeModal/components/SearchTitle.js +15 -18
- package/es/ProTreeModal/components/SortableItem.js +29 -58
- package/es/ProTreeModal/components/Tree.js +99 -113
- package/es/ProTreeModal/components/Trigger.js +87 -121
- package/es/ProTreeModal/components/index.js +14 -6
- package/es/ProTreeModal/index.js +397 -435
- package/es/ProTreeModal/propsType.js +0 -1
- package/es/ProTreeModal/utils.js +52 -95
- package/es/ProUpload/components/ButtonRender.js +44 -54
- package/es/ProUpload/components/DragRender.js +94 -134
- package/es/ProUpload/components/DraggableUploadListItem.js +12 -25
- package/es/ProUpload/components/Example.js +27 -31
- package/es/ProUpload/components/FileItem.js +69 -163
- package/es/ProUpload/components/ImageRender.js +134 -170
- package/es/ProUpload/index.js +68 -100
- package/es/ProUpload/propsType.js +0 -1
- package/es/ProUpload/uitls.js +8 -4
- package/es/ProUtils/utils/index.js +17 -13
- package/es/ProViewer/index.js +154 -175
- package/es/ProViewer/propsType.js +0 -5
- package/es/ProWaterMark/index.js +9 -16
- package/es/ProWaterMark/propsType.js +0 -1
- package/es/hooks/useDraggableRow.js +25 -53
- package/es/index.js +57 -77
- package/es/locale/en_US.js +153 -142
- package/es/locale/index.js +23 -36
- package/es/locale/zh_CN.js +145 -142
- package/es/tokens.js +84 -83
- package/es/utils/index.js +24 -51
- package/package.json +4 -3
|
@@ -1,315 +1,263 @@
|
|
|
1
|
-
import { useState, useCallback, useEffect, useRef } from
|
|
2
|
-
import { message } from
|
|
1
|
+
import { useState, useCallback, useEffect, useRef } from "react";
|
|
2
|
+
import { message } from "antd";
|
|
3
3
|
import { DEFAULT_TABS_CONFIG } from "../propTypes";
|
|
4
4
|
import { useTabsCache } from "./useTabsCache";
|
|
5
5
|
import locale, { formatMessage } from "../../../../locale";
|
|
6
|
-
import {
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
6
|
+
import {
|
|
7
|
+
createTabFromMenu,
|
|
8
|
+
generateTabId,
|
|
9
|
+
shouldOpenExternal,
|
|
10
|
+
handleExternalOpen,
|
|
11
|
+
checkTabLimit,
|
|
12
|
+
getRightTabs,
|
|
13
|
+
flattenMenuData,
|
|
14
|
+
canOpenAsTab,
|
|
15
|
+
getMenuRoute,
|
|
16
|
+
hasRelationKey,
|
|
17
|
+
findExistingTab,
|
|
18
|
+
normalizeTabUrl,
|
|
19
|
+
isSafeExternalUrl,
|
|
20
|
+
isSafeHttpUrl,
|
|
21
|
+
resolveTabMenuItem,
|
|
22
|
+
derivePinned,
|
|
23
|
+
getPinnedBoundary,
|
|
24
|
+
pinTab as pinTabInList,
|
|
25
|
+
unpinTab as unpinTabInList,
|
|
26
|
+
reorderWithPinConstraint
|
|
27
|
+
} from "../utils";
|
|
28
|
+
const useTabsState = (options) => {
|
|
29
|
+
const { initialState = {}, config, dataSource, cacheEnabled = true } = options;
|
|
30
|
+
const finalConfig = { ...DEFAULT_TABS_CONFIG, ...config };
|
|
31
|
+
const urlSyncEnabled = finalConfig.urlSync === true || typeof finalConfig.urlSync === "object" && finalConfig.urlSync !== null;
|
|
32
|
+
const urlSyncIdentity = typeof finalConfig.urlSync === "object" && finalConfig.urlSync !== null ? finalConfig.urlSync.identity || "url" : "url";
|
|
27
33
|
const [state, setState] = useState(() => ({
|
|
28
34
|
tabsList: [],
|
|
29
|
-
activeKey:
|
|
30
|
-
activeTabInfo:
|
|
35
|
+
activeKey: "",
|
|
36
|
+
activeTabInfo: void 0,
|
|
31
37
|
newTabIndex: 0,
|
|
32
|
-
activeComponent:
|
|
38
|
+
activeComponent: "",
|
|
33
39
|
...initialState
|
|
34
40
|
}));
|
|
35
|
-
|
|
36
|
-
// 缓存管理
|
|
37
|
-
const {
|
|
38
|
-
saveToCache,
|
|
39
|
-
restoreFromCache,
|
|
40
|
-
clearCache
|
|
41
|
-
} = useTabsCache({
|
|
41
|
+
const { saveToCache, restoreFromCache, clearCache } = useTabsCache({
|
|
42
42
|
cacheKey: finalConfig.cacheKey,
|
|
43
43
|
storage: finalConfig.storage,
|
|
44
44
|
enabled: cacheEnabled
|
|
45
45
|
});
|
|
46
|
-
|
|
47
|
-
// 初始化标记,确保只在初始化后保存缓存
|
|
48
46
|
const [isInitialized, setIsInitialized] = useState(false);
|
|
49
|
-
|
|
50
|
-
// 从缓存恢复状态
|
|
51
47
|
const hasRestoredCacheRef = useRef(false);
|
|
52
48
|
useEffect(() => {
|
|
53
|
-
|
|
49
|
+
var _a, _b;
|
|
50
|
+
if (hasRestoredCacheRef.current)
|
|
51
|
+
return;
|
|
54
52
|
hasRestoredCacheRef.current = true;
|
|
55
53
|
const cachedState = restoreFromCache();
|
|
56
54
|
if (cachedState && cachedState.tabsList && cachedState.tabsList.length > 0) {
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
...cachedState
|
|
60
|
-
};
|
|
61
|
-
if ('activeTab' in restoredState && !restoredState.activeTabInfo) {
|
|
55
|
+
const restoredState = { ...cachedState };
|
|
56
|
+
if ("activeTab" in restoredState && !restoredState.activeTabInfo) {
|
|
62
57
|
restoredState.activeTabInfo = restoredState.activeTab;
|
|
63
58
|
delete restoredState.activeTab;
|
|
64
59
|
}
|
|
65
|
-
|
|
66
|
-
// 兼容旧缓存:Ant Tabs 的 onChange 始终返回字符串 key;旧版本可能保存数字 id,
|
|
67
|
-
// 若不归一化,严格比较会导致恢复后的标签无法切换。
|
|
68
|
-
restoredState.tabsList = restoredState.tabsList.map(tab => ({
|
|
60
|
+
restoredState.tabsList = restoredState.tabsList.map((tab) => ({
|
|
69
61
|
...tab,
|
|
70
62
|
id: String(tab.id),
|
|
71
|
-
pinned: tab.pinned ===
|
|
63
|
+
pinned: tab.pinned === void 0 ? derivePinned(tab) : tab.pinned
|
|
72
64
|
}));
|
|
73
|
-
restoredState.activeKey = restoredState.activeKey ===
|
|
65
|
+
restoredState.activeKey = restoredState.activeKey === void 0 || restoredState.activeKey === null ? "" : String(restoredState.activeKey);
|
|
74
66
|
if (urlSyncEnabled) {
|
|
75
|
-
const
|
|
76
|
-
const retainedIdByOriginalId = new Map();
|
|
77
|
-
restoredState.tabsList.forEach(tab => {
|
|
67
|
+
const retainedTabByIdentity = /* @__PURE__ */ new Map();
|
|
68
|
+
const retainedIdByOriginalId = /* @__PURE__ */ new Map();
|
|
69
|
+
restoredState.tabsList.forEach((tab) => {
|
|
70
|
+
var _a2;
|
|
78
71
|
const normalizedUrl = normalizeTabUrl(tab.url);
|
|
79
|
-
if (!normalizedUrl)
|
|
80
|
-
|
|
72
|
+
if (!normalizedUrl)
|
|
73
|
+
return;
|
|
74
|
+
const relationKey = tab.relationKey ?? ((_a2 = tab.menuItem) == null ? void 0 : _a2.relationKey);
|
|
75
|
+
const identity = urlSyncIdentity === "relationKey" && hasRelationKey(relationKey) ? `relationKey:${typeof relationKey}:${String(relationKey)}` : `url:${normalizedUrl}`;
|
|
76
|
+
const retainedTab = retainedTabByIdentity.get(identity);
|
|
81
77
|
if (retainedTab) {
|
|
78
|
+
retainedTabByIdentity.set(identity, { ...retainedTab, url: normalizedUrl });
|
|
82
79
|
retainedIdByOriginalId.set(tab.id, retainedTab.id);
|
|
83
80
|
return;
|
|
84
81
|
}
|
|
85
|
-
const normalizedTab = {
|
|
86
|
-
|
|
87
|
-
url: normalizedUrl
|
|
88
|
-
};
|
|
89
|
-
retainedTabByUrl.set(normalizedUrl, normalizedTab);
|
|
82
|
+
const normalizedTab = { ...tab, url: normalizedUrl };
|
|
83
|
+
retainedTabByIdentity.set(identity, normalizedTab);
|
|
90
84
|
retainedIdByOriginalId.set(tab.id, normalizedTab.id);
|
|
91
85
|
});
|
|
92
|
-
restoredState.tabsList = Array.from(
|
|
93
|
-
restoredState.activeKey = retainedIdByOriginalId.get(restoredState.activeKey) || restoredState.tabsList[0]
|
|
86
|
+
restoredState.tabsList = Array.from(retainedTabByIdentity.values());
|
|
87
|
+
restoredState.activeKey = retainedIdByOriginalId.get(restoredState.activeKey) || ((_a = restoredState.tabsList[0]) == null ? void 0 : _a.id) || "";
|
|
94
88
|
}
|
|
95
|
-
restoredState.activeTabInfo = restoredState.tabsList.find(
|
|
96
|
-
|
|
89
|
+
restoredState.activeTabInfo = restoredState.tabsList.find(
|
|
90
|
+
(tab) => tab.id === restoredState.activeKey
|
|
91
|
+
);
|
|
92
|
+
restoredState.activeComponent = restoredState.activeTabInfo ? ((_b = restoredState.activeTabInfo.menuItem) == null ? void 0 : _b.code) || restoredState.activeTabInfo.id : "";
|
|
97
93
|
setState(restoredState);
|
|
98
94
|
}
|
|
99
95
|
setIsInitialized(true);
|
|
100
|
-
}, [restoreFromCache, urlSyncEnabled]);
|
|
101
|
-
const lastActiveKeyRef = useRef(
|
|
96
|
+
}, [restoreFromCache, urlSyncEnabled, urlSyncIdentity]);
|
|
97
|
+
const lastActiveKeyRef = useRef("");
|
|
102
98
|
const shouldSkipSaveRef = useRef(false);
|
|
103
99
|
const initialTabsAppliedRef = useRef(false);
|
|
104
|
-
|
|
105
|
-
// 保存状态到缓存
|
|
106
100
|
useEffect(() => {
|
|
107
|
-
if (!isInitialized)
|
|
108
|
-
|
|
109
|
-
// 如果标记了跳过保存(清空缓存后),则跳过本次保存
|
|
101
|
+
if (!isInitialized)
|
|
102
|
+
return;
|
|
110
103
|
if (shouldSkipSaveRef.current) {
|
|
111
104
|
shouldSkipSaveRef.current = false;
|
|
112
105
|
return;
|
|
113
106
|
}
|
|
114
|
-
|
|
115
|
-
// 处理 onTabChange 调用 - 支持空状态和正常切换
|
|
116
107
|
if (finalConfig.onTabChange && lastActiveKeyRef.current !== state.activeKey) {
|
|
117
108
|
lastActiveKeyRef.current = state.activeKey;
|
|
118
109
|
if (state.activeKey) {
|
|
119
|
-
|
|
120
|
-
const activeTab = state.tabsList.find(tab => tab.id === state.activeKey);
|
|
110
|
+
const activeTab = state.tabsList.find((tab) => tab.id === state.activeKey);
|
|
121
111
|
if (activeTab) {
|
|
122
112
|
finalConfig.onTabChange(state.activeKey, activeTab, state.tabsList);
|
|
123
113
|
}
|
|
124
114
|
} else {
|
|
125
|
-
|
|
126
|
-
finalConfig.onTabChange('', undefined, state.tabsList);
|
|
115
|
+
finalConfig.onTabChange("", void 0, state.tabsList);
|
|
127
116
|
}
|
|
128
117
|
}
|
|
129
|
-
|
|
130
|
-
// 如果 tabsList 为空且 activeKey 为空,说明是清空状态,不保存缓存
|
|
131
118
|
if (state.tabsList.length === 0 && !state.activeKey) {
|
|
132
119
|
return;
|
|
133
120
|
}
|
|
134
|
-
|
|
135
|
-
// 保存状态到缓存
|
|
136
121
|
saveToCache(state);
|
|
137
122
|
}, [state, saveToCache, finalConfig, isInitialized]);
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
const {
|
|
144
|
-
forceNew = false
|
|
145
|
-
} = options || {};
|
|
146
|
-
|
|
147
|
-
// 非叶子节点默认不入签,仅根节点特例可入签
|
|
148
|
-
if (!canOpenAsTab(menuItem)) {
|
|
149
|
-
return false;
|
|
150
|
-
}
|
|
151
|
-
|
|
152
|
-
// 检查是否需要外部跳转
|
|
153
|
-
if (shouldOpenExternal(menuItem)) {
|
|
154
|
-
return false;
|
|
155
|
-
}
|
|
156
|
-
|
|
157
|
-
// URL 同步模式下完整 URL 始终唯一,forceNew 不能绕过身份匹配。
|
|
158
|
-
if (urlSyncEnabled || !forceNew) {
|
|
159
|
-
const existingTab = findExistingTab(state.tabsList, menuItem, {
|
|
160
|
-
urlSync: urlSyncEnabled
|
|
161
|
-
});
|
|
162
|
-
if (existingTab) {
|
|
163
|
-
// 如果已存在,可以添加(会切换到已存在的标签页)
|
|
164
|
-
return true;
|
|
123
|
+
const canAddTab = useCallback(
|
|
124
|
+
(menuItem, options2) => {
|
|
125
|
+
const { forceNew = false } = options2 || {};
|
|
126
|
+
if (!canOpenAsTab(menuItem)) {
|
|
127
|
+
return false;
|
|
165
128
|
}
|
|
166
|
-
}
|
|
167
|
-
|
|
168
|
-
// 检查是否超出限制(只有在需要创建新标签页时才检查)
|
|
169
|
-
if (checkTabLimit(state.tabsList, finalConfig.max)) {
|
|
170
|
-
// 达到最大值时,不能添加新标签页
|
|
171
|
-
return false;
|
|
172
|
-
}
|
|
173
|
-
return true;
|
|
174
|
-
}, [state.tabsList, finalConfig, urlSyncEnabled]);
|
|
175
|
-
|
|
176
|
-
/**
|
|
177
|
-
* 添加标签页
|
|
178
|
-
*/
|
|
179
|
-
const addTab = useCallback((menuItem, options) => {
|
|
180
|
-
const {
|
|
181
|
-
forceNew = false,
|
|
182
|
-
silent = false
|
|
183
|
-
} = options || {};
|
|
184
|
-
setState(prevState => {
|
|
185
|
-
if (!canOpenAsTab(menuItem)) return prevState;
|
|
186
129
|
if (shouldOpenExternal(menuItem)) {
|
|
187
|
-
|
|
188
|
-
if (!urlSyncEnabled || isSafeHttpUrl(externalUrl)) {
|
|
189
|
-
handleExternalOpen(menuItem, urlSyncEnabled);
|
|
190
|
-
}
|
|
191
|
-
return prevState;
|
|
130
|
+
return false;
|
|
192
131
|
}
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
132
|
+
if (urlSyncEnabled || !forceNew) {
|
|
133
|
+
const existingTab = findExistingTab(state.tabsList, menuItem, {
|
|
134
|
+
urlSync: urlSyncEnabled,
|
|
135
|
+
identity: urlSyncIdentity
|
|
136
|
+
});
|
|
137
|
+
if (existingTab) {
|
|
138
|
+
return true;
|
|
198
139
|
}
|
|
199
|
-
return prevState;
|
|
200
140
|
}
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
}
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
141
|
+
if (checkTabLimit(state.tabsList, finalConfig.max)) {
|
|
142
|
+
return false;
|
|
143
|
+
}
|
|
144
|
+
return true;
|
|
145
|
+
},
|
|
146
|
+
[state.tabsList, finalConfig, urlSyncEnabled, urlSyncIdentity]
|
|
147
|
+
);
|
|
148
|
+
const addTab = useCallback(
|
|
149
|
+
(menuItem, options2) => {
|
|
150
|
+
const { forceNew = false, silent = false } = options2 || {};
|
|
151
|
+
setState((prevState) => {
|
|
152
|
+
var _a;
|
|
153
|
+
if (!canOpenAsTab(menuItem))
|
|
154
|
+
return prevState;
|
|
155
|
+
if (shouldOpenExternal(menuItem)) {
|
|
156
|
+
const externalUrl = getMenuRoute(menuItem);
|
|
157
|
+
if (!urlSyncEnabled || isSafeHttpUrl(externalUrl)) {
|
|
158
|
+
handleExternalOpen(menuItem, urlSyncEnabled);
|
|
159
|
+
}
|
|
160
|
+
return prevState;
|
|
161
|
+
}
|
|
162
|
+
const rawUrl = getMenuRoute(menuItem);
|
|
163
|
+
const normalizedUrl = urlSyncEnabled ? normalizeTabUrl(rawUrl) : void 0;
|
|
164
|
+
if (urlSyncEnabled && rawUrl && !normalizedUrl) {
|
|
165
|
+
if (isSafeExternalUrl(rawUrl)) {
|
|
166
|
+
handleExternalOpen(menuItem, true);
|
|
167
|
+
}
|
|
168
|
+
return prevState;
|
|
169
|
+
}
|
|
170
|
+
const resolvedMenuItem = normalizedUrl ? { ...menuItem, url: normalizedUrl, redirectUrl: void 0 } : menuItem;
|
|
171
|
+
const existingTab = urlSyncEnabled || !forceNew ? findExistingTab(prevState.tabsList, resolvedMenuItem, {
|
|
172
|
+
urlSync: urlSyncEnabled,
|
|
173
|
+
identity: urlSyncIdentity
|
|
174
|
+
}) : void 0;
|
|
175
|
+
if (existingTab) {
|
|
176
|
+
const shouldFixClosable = resolvedMenuItem.closable === false && existingTab.closable !== false;
|
|
177
|
+
const shouldUpdateUrl = urlSyncIdentity === "relationKey" && normalizedUrl !== void 0 && existingTab.url !== normalizedUrl;
|
|
178
|
+
const correctedTab = shouldFixClosable || shouldUpdateUrl ? {
|
|
179
|
+
...existingTab,
|
|
180
|
+
...shouldFixClosable ? { closable: false } : {},
|
|
181
|
+
...shouldUpdateUrl ? { url: normalizedUrl } : {}
|
|
182
|
+
} : existingTab;
|
|
183
|
+
const updatedTabsList = correctedTab !== existingTab ? prevState.tabsList.map((t) => t.id === existingTab.id ? correctedTab : t) : prevState.tabsList;
|
|
184
|
+
return {
|
|
185
|
+
...prevState,
|
|
186
|
+
tabsList: updatedTabsList,
|
|
187
|
+
activeKey: existingTab.id,
|
|
188
|
+
activeTabInfo: correctedTab,
|
|
189
|
+
activeComponent: ((_a = existingTab.menuItem) == null ? void 0 : _a.code) || existingTab.id
|
|
190
|
+
};
|
|
191
|
+
}
|
|
192
|
+
if (checkTabLimit(prevState.tabsList, finalConfig.max)) {
|
|
193
|
+
message.info(
|
|
194
|
+
formatMessage(locale.ProLayout.tabMaxLimitMessage, { max: finalConfig.max })
|
|
195
|
+
);
|
|
196
|
+
return prevState;
|
|
197
|
+
}
|
|
198
|
+
const existingIds = prevState.tabsList.map((tab) => tab.id);
|
|
199
|
+
const tabId = generateTabId(resolvedMenuItem, existingIds);
|
|
200
|
+
const newTab = createTabFromMenu(resolvedMenuItem, prevState.newTabIndex);
|
|
201
|
+
newTab.id = tabId;
|
|
202
|
+
const pinnedBoundary = getPinnedBoundary(prevState.tabsList);
|
|
203
|
+
const nextTabsList = derivePinned(newTab) ? [
|
|
204
|
+
...prevState.tabsList.slice(0, pinnedBoundary),
|
|
205
|
+
newTab,
|
|
206
|
+
...prevState.tabsList.slice(pinnedBoundary)
|
|
207
|
+
] : [...prevState.tabsList, newTab];
|
|
208
|
+
const shouldActivate = !silent || prevState.activeKey === "";
|
|
218
209
|
return {
|
|
219
210
|
...prevState,
|
|
220
|
-
tabsList:
|
|
221
|
-
activeKey:
|
|
222
|
-
activeTabInfo:
|
|
223
|
-
|
|
211
|
+
tabsList: nextTabsList,
|
|
212
|
+
activeKey: shouldActivate ? tabId : prevState.activeKey,
|
|
213
|
+
activeTabInfo: shouldActivate ? newTab : prevState.activeTabInfo,
|
|
214
|
+
newTabIndex: prevState.newTabIndex + 1,
|
|
215
|
+
activeComponent: shouldActivate ? resolvedMenuItem.code || tabId : prevState.activeComponent
|
|
224
216
|
};
|
|
225
|
-
}
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
}));
|
|
230
|
-
return prevState;
|
|
231
|
-
}
|
|
232
|
-
const existingIds = prevState.tabsList.map(tab => tab.id);
|
|
233
|
-
const tabId = generateTabId(resolvedMenuItem, existingIds);
|
|
234
|
-
const newTab = createTabFromMenu(resolvedMenuItem, prevState.newTabIndex);
|
|
235
|
-
newTab.id = tabId;
|
|
236
|
-
const pinnedBoundary = getPinnedBoundary(prevState.tabsList);
|
|
237
|
-
const nextTabsList = derivePinned(newTab) ? [...prevState.tabsList.slice(0, pinnedBoundary), newTab, ...prevState.tabsList.slice(pinnedBoundary)] : [...prevState.tabsList, newTab];
|
|
238
|
-
|
|
239
|
-
// silent=true 时,若已有 active 则保留;无 active(首次进入)仍激活以保留默认行为
|
|
240
|
-
const shouldActivate = !silent || prevState.activeKey === '';
|
|
241
|
-
return {
|
|
242
|
-
...prevState,
|
|
243
|
-
tabsList: nextTabsList,
|
|
244
|
-
activeKey: shouldActivate ? tabId : prevState.activeKey,
|
|
245
|
-
activeTabInfo: shouldActivate ? newTab : prevState.activeTabInfo,
|
|
246
|
-
newTabIndex: prevState.newTabIndex + 1,
|
|
247
|
-
activeComponent: shouldActivate ? resolvedMenuItem.code || tabId : prevState.activeComponent
|
|
248
|
-
};
|
|
249
|
-
});
|
|
250
|
-
}, [finalConfig, urlSyncEnabled]);
|
|
251
|
-
|
|
252
|
-
// 普通初始标签只在当前 TabsManager 挂载周期应用一次。
|
|
253
|
-
// 缓存恢复已有标签时只消费默认值;closeAll 后 ref 保持 true,避免再次补签。
|
|
217
|
+
});
|
|
218
|
+
},
|
|
219
|
+
[finalConfig, urlSyncEnabled, urlSyncIdentity]
|
|
220
|
+
);
|
|
254
221
|
useEffect(() => {
|
|
255
222
|
const initialTabs = finalConfig.initialTabs;
|
|
256
223
|
if (!isInitialized || !cacheEnabled || initialTabsAppliedRef.current || !initialTabs || initialTabs.length === 0) {
|
|
257
224
|
return;
|
|
258
225
|
}
|
|
259
226
|
initialTabsAppliedRef.current = true;
|
|
260
|
-
if (state.tabsList.length > 0)
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
});
|
|
227
|
+
if (state.tabsList.length > 0)
|
|
228
|
+
return;
|
|
229
|
+
const sourceMenus = Array.isArray(dataSource == null ? void 0 : dataSource.menus) ? dataSource.menus : [];
|
|
230
|
+
initialTabs.forEach((params) => {
|
|
231
|
+
addTab(resolveTabMenuItem(params, sourceMenus), { silent: true });
|
|
266
232
|
});
|
|
267
|
-
}, [
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
233
|
+
}, [
|
|
234
|
+
isInitialized,
|
|
235
|
+
cacheEnabled,
|
|
236
|
+
finalConfig.initialTabs,
|
|
237
|
+
dataSource,
|
|
238
|
+
state.tabsList.length,
|
|
239
|
+
addTab
|
|
240
|
+
]);
|
|
275
241
|
const updateTab = useCallback((tabId, updates) => {
|
|
276
|
-
setState(prevState => {
|
|
277
|
-
const targetIndex = prevState.tabsList.findIndex(tab => tab.id === tabId);
|
|
278
|
-
if (targetIndex === -1)
|
|
242
|
+
setState((prevState) => {
|
|
243
|
+
const targetIndex = prevState.tabsList.findIndex((tab) => tab.id === tabId);
|
|
244
|
+
if (targetIndex === -1)
|
|
245
|
+
return prevState;
|
|
279
246
|
const target = prevState.tabsList[targetIndex];
|
|
280
247
|
const nextMenuItem = target.menuItem ? {
|
|
281
248
|
...target.menuItem,
|
|
282
|
-
...
|
|
283
|
-
|
|
284
|
-
}
|
|
285
|
-
...
|
|
286
|
-
|
|
287
|
-
}),
|
|
288
|
-
...(updates.extra !== undefined && {
|
|
289
|
-
extra: updates.extra
|
|
290
|
-
}),
|
|
291
|
-
...(updates.closable !== undefined && {
|
|
292
|
-
closable: updates.closable
|
|
293
|
-
}),
|
|
294
|
-
...(updates.pinned !== undefined && {
|
|
295
|
-
pinned: updates.pinned
|
|
296
|
-
})
|
|
249
|
+
...updates.name !== void 0 && { name: updates.name },
|
|
250
|
+
...updates.icon !== void 0 && { icon: updates.icon },
|
|
251
|
+
...updates.extra !== void 0 && { extra: updates.extra },
|
|
252
|
+
...updates.closable !== void 0 && { closable: updates.closable },
|
|
253
|
+
...updates.pinned !== void 0 && { pinned: updates.pinned }
|
|
297
254
|
} : target.menuItem;
|
|
298
255
|
const nextTab = {
|
|
299
256
|
...target,
|
|
300
|
-
...
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
}
|
|
304
|
-
...(updates.icon !== undefined && {
|
|
305
|
-
icon: updates.icon
|
|
306
|
-
}),
|
|
307
|
-
...(updates.closable !== undefined && {
|
|
308
|
-
closable: updates.closable
|
|
309
|
-
}),
|
|
310
|
-
...(updates.pinned !== undefined && {
|
|
311
|
-
pinned: updates.pinned
|
|
312
|
-
}),
|
|
257
|
+
...updates.name !== void 0 && { name: updates.name, title: updates.name },
|
|
258
|
+
...updates.icon !== void 0 && { icon: updates.icon },
|
|
259
|
+
...updates.closable !== void 0 && { closable: updates.closable },
|
|
260
|
+
...updates.pinned !== void 0 && { pinned: updates.pinned },
|
|
313
261
|
menuItem: nextMenuItem
|
|
314
262
|
};
|
|
315
263
|
const newTabsList = [...prevState.tabsList];
|
|
@@ -321,105 +269,89 @@ export const useTabsState = options => {
|
|
|
321
269
|
};
|
|
322
270
|
});
|
|
323
271
|
}, []);
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
if (!tabToRemove || !tabToRemove.closable) {
|
|
332
|
-
return prevState;
|
|
333
|
-
}
|
|
334
|
-
const newTabs = prevState.tabsList.filter(tab => tab.id !== tabId);
|
|
335
|
-
let newActiveKey = prevState.activeKey;
|
|
336
|
-
let newActiveTabInfo = prevState.activeTabInfo;
|
|
337
|
-
let newActiveComponent = prevState.activeComponent;
|
|
338
|
-
|
|
339
|
-
// 如果移除的是当前活跃标签页,需要选择新的活跃标签页
|
|
340
|
-
if (prevState.activeKey === tabId && newTabs.length > 0) {
|
|
341
|
-
const currentIndex = prevState.tabsList.findIndex(tab => tab.id === tabId);
|
|
342
|
-
const newActiveIndex = Math.min(currentIndex, newTabs.length - 1);
|
|
343
|
-
newActiveTabInfo = newTabs[newActiveIndex];
|
|
344
|
-
newActiveKey = newActiveTabInfo.id;
|
|
345
|
-
newActiveComponent = newActiveTabInfo.menuItem?.code || newActiveTabInfo.id;
|
|
346
|
-
} else if (prevState.activeKey === tabId) {
|
|
347
|
-
// 如果删除后没有标签页了
|
|
348
|
-
newActiveKey = '';
|
|
349
|
-
newActiveTabInfo = undefined;
|
|
350
|
-
newActiveComponent = '';
|
|
351
|
-
}
|
|
352
|
-
|
|
353
|
-
// 如果删除后没有标签页了,清空缓存
|
|
354
|
-
if (newTabs.length === 0) {
|
|
355
|
-
// 标记跳过下次保存,避免清空后又被重新保存
|
|
356
|
-
shouldSkipSaveRef.current = true;
|
|
357
|
-
clearCache();
|
|
358
|
-
|
|
359
|
-
// 直接调用 onTabChange,因为 useEffect 会被跳过
|
|
360
|
-
if (finalConfig.onTabChange) {
|
|
361
|
-
setTimeout(() => {
|
|
362
|
-
finalConfig.onTabChange('', undefined, []);
|
|
363
|
-
}, 0);
|
|
272
|
+
const removeTab = useCallback(
|
|
273
|
+
(tabId) => {
|
|
274
|
+
setState((prevState) => {
|
|
275
|
+
var _a;
|
|
276
|
+
const tabToRemove = prevState.tabsList.find((tab) => tab.id === tabId);
|
|
277
|
+
if (!tabToRemove || !tabToRemove.closable) {
|
|
278
|
+
return prevState;
|
|
364
279
|
}
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
activeKey
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
280
|
+
const newTabs = prevState.tabsList.filter((tab) => tab.id !== tabId);
|
|
281
|
+
let newActiveKey = prevState.activeKey;
|
|
282
|
+
let newActiveTabInfo = prevState.activeTabInfo;
|
|
283
|
+
let newActiveComponent = prevState.activeComponent;
|
|
284
|
+
if (prevState.activeKey === tabId && newTabs.length > 0) {
|
|
285
|
+
const currentIndex = prevState.tabsList.findIndex((tab) => tab.id === tabId);
|
|
286
|
+
const newActiveIndex = Math.min(currentIndex, newTabs.length - 1);
|
|
287
|
+
newActiveTabInfo = newTabs[newActiveIndex];
|
|
288
|
+
newActiveKey = newActiveTabInfo.id;
|
|
289
|
+
newActiveComponent = ((_a = newActiveTabInfo.menuItem) == null ? void 0 : _a.code) || newActiveTabInfo.id;
|
|
290
|
+
} else if (prevState.activeKey === tabId) {
|
|
291
|
+
newActiveKey = "";
|
|
292
|
+
newActiveTabInfo = void 0;
|
|
293
|
+
newActiveComponent = "";
|
|
294
|
+
}
|
|
295
|
+
if (newTabs.length === 0) {
|
|
296
|
+
shouldSkipSaveRef.current = true;
|
|
297
|
+
clearCache();
|
|
298
|
+
if (finalConfig.onTabChange) {
|
|
299
|
+
setTimeout(() => {
|
|
300
|
+
finalConfig.onTabChange("", void 0, []);
|
|
301
|
+
}, 0);
|
|
302
|
+
}
|
|
303
|
+
}
|
|
304
|
+
return {
|
|
305
|
+
...prevState,
|
|
306
|
+
tabsList: newTabs,
|
|
307
|
+
activeKey: newActiveKey,
|
|
308
|
+
activeTabInfo: newActiveTabInfo,
|
|
309
|
+
activeComponent: newActiveComponent
|
|
310
|
+
};
|
|
311
|
+
});
|
|
312
|
+
},
|
|
313
|
+
[clearCache, finalConfig]
|
|
314
|
+
);
|
|
315
|
+
const switchTab = useCallback((tabId) => {
|
|
316
|
+
setState((prevState) => {
|
|
317
|
+
var _a;
|
|
318
|
+
const targetTab = prevState.tabsList.find((tab) => tab.id === tabId);
|
|
319
|
+
if (!targetTab)
|
|
320
|
+
return prevState;
|
|
383
321
|
const newState = {
|
|
384
322
|
...prevState,
|
|
385
323
|
activeKey: tabId,
|
|
386
324
|
activeTabInfo: targetTab,
|
|
387
|
-
activeComponent: targetTab.menuItem
|
|
325
|
+
activeComponent: ((_a = targetTab.menuItem) == null ? void 0 : _a.code) || tabId
|
|
388
326
|
};
|
|
389
327
|
return newState;
|
|
390
328
|
});
|
|
391
329
|
}, []);
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
/**
|
|
413
|
-
* 更新页签当前 URL,保持 tab.id 和 menuItem 的菜单基础路由不变。
|
|
414
|
-
*/
|
|
330
|
+
const rollbackTabActivation = useCallback(
|
|
331
|
+
(previousTabId, attemptedTabId, removeAttemptedTab) => {
|
|
332
|
+
setState((prevState) => {
|
|
333
|
+
var _a;
|
|
334
|
+
if (prevState.activeKey !== attemptedTabId)
|
|
335
|
+
return prevState;
|
|
336
|
+
const nextTabsList = removeAttemptedTab ? prevState.tabsList.filter((tab) => tab.id !== attemptedTabId) : prevState.tabsList;
|
|
337
|
+
const previousTab = nextTabsList.find((tab) => tab.id === previousTabId);
|
|
338
|
+
return {
|
|
339
|
+
...prevState,
|
|
340
|
+
tabsList: nextTabsList,
|
|
341
|
+
activeKey: (previousTab == null ? void 0 : previousTab.id) || "",
|
|
342
|
+
activeTabInfo: previousTab,
|
|
343
|
+
activeComponent: previousTab ? ((_a = previousTab.menuItem) == null ? void 0 : _a.code) || previousTab.id : ""
|
|
344
|
+
};
|
|
345
|
+
});
|
|
346
|
+
},
|
|
347
|
+
[]
|
|
348
|
+
);
|
|
415
349
|
const updateTabUrl = useCallback((tabId, url) => {
|
|
416
|
-
setState(prevState => {
|
|
417
|
-
const targetIndex = prevState.tabsList.findIndex(tab => tab.id === tabId);
|
|
418
|
-
if (targetIndex === -1 || prevState.tabsList[targetIndex].url === url)
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
url
|
|
422
|
-
};
|
|
350
|
+
setState((prevState) => {
|
|
351
|
+
const targetIndex = prevState.tabsList.findIndex((tab) => tab.id === tabId);
|
|
352
|
+
if (targetIndex === -1 || prevState.tabsList[targetIndex].url === url)
|
|
353
|
+
return prevState;
|
|
354
|
+
const nextTab = { ...prevState.tabsList[targetIndex], url };
|
|
423
355
|
const nextTabsList = [...prevState.tabsList];
|
|
424
356
|
nextTabsList[targetIndex] = nextTab;
|
|
425
357
|
return {
|
|
@@ -429,150 +361,113 @@ export const useTabsState = options => {
|
|
|
429
361
|
};
|
|
430
362
|
});
|
|
431
363
|
}, []);
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
const
|
|
439
|
-
if (!currentTab) return prevState;
|
|
440
|
-
|
|
441
|
-
// 只保留当前标签页和不可关闭的标签页
|
|
442
|
-
const newTabs = prevState.tabsList.filter(tab => tab.id === currentTabId || !tab.closable);
|
|
364
|
+
const closeOtherTabs = useCallback((currentTabId) => {
|
|
365
|
+
setState((prevState) => {
|
|
366
|
+
var _a;
|
|
367
|
+
const currentTab = prevState.tabsList.find((tab) => tab.id === currentTabId);
|
|
368
|
+
if (!currentTab)
|
|
369
|
+
return prevState;
|
|
370
|
+
const newTabs = prevState.tabsList.filter((tab) => tab.id === currentTabId || !tab.closable);
|
|
443
371
|
return {
|
|
444
372
|
...prevState,
|
|
445
373
|
tabsList: newTabs,
|
|
446
374
|
activeKey: currentTabId,
|
|
447
375
|
activeTabInfo: currentTab,
|
|
448
|
-
activeComponent: currentTab.menuItem
|
|
376
|
+
activeComponent: ((_a = currentTab.menuItem) == null ? void 0 : _a.code) || currentTabId
|
|
449
377
|
};
|
|
450
378
|
});
|
|
451
379
|
}, []);
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
* 关闭右侧标签页
|
|
455
|
-
*/
|
|
456
|
-
const closeRightTabs = useCallback(currentTabId => {
|
|
457
|
-
setState(prevState => {
|
|
380
|
+
const closeRightTabs = useCallback((currentTabId) => {
|
|
381
|
+
setState((prevState) => {
|
|
458
382
|
const rightTabs = getRightTabs(prevState.tabsList, currentTabId);
|
|
459
|
-
const tabsToKeep = prevState.tabsList.filter(
|
|
383
|
+
const tabsToKeep = prevState.tabsList.filter(
|
|
384
|
+
(tab) => !rightTabs.includes(tab) || !tab.closable
|
|
385
|
+
);
|
|
460
386
|
return {
|
|
461
387
|
...prevState,
|
|
462
388
|
tabsList: tabsToKeep
|
|
463
389
|
};
|
|
464
390
|
});
|
|
465
391
|
}, []);
|
|
466
|
-
|
|
467
|
-
/**
|
|
468
|
-
* 关闭全部标签页
|
|
469
|
-
*/
|
|
470
392
|
const closeAllTabs = useCallback(() => {
|
|
471
|
-
setState(prevState => {
|
|
472
|
-
|
|
473
|
-
const newTabs = prevState.tabsList.filter(tab => !tab.closable);
|
|
474
|
-
let newActiveKey =
|
|
475
|
-
let newActiveComponent =
|
|
393
|
+
setState((prevState) => {
|
|
394
|
+
var _a;
|
|
395
|
+
const newTabs = prevState.tabsList.filter((tab) => !tab.closable);
|
|
396
|
+
let newActiveKey = "";
|
|
397
|
+
let newActiveComponent = "";
|
|
476
398
|
if (newTabs.length > 0) {
|
|
477
399
|
const firstTab = newTabs[0];
|
|
478
400
|
newActiveKey = firstTab.id;
|
|
479
|
-
newActiveComponent = firstTab.menuItem
|
|
401
|
+
newActiveComponent = ((_a = firstTab.menuItem) == null ? void 0 : _a.code) || firstTab.id;
|
|
480
402
|
}
|
|
481
|
-
|
|
482
|
-
// 关闭全部标签页时,清空缓存
|
|
483
|
-
// 标记跳过下次保存,避免清空后又被重新保存
|
|
484
403
|
shouldSkipSaveRef.current = true;
|
|
485
404
|
clearCache();
|
|
486
|
-
|
|
487
|
-
// 直接调用 onTabChange(useEffect 因 shouldSkipSaveRef 会跳过)
|
|
488
405
|
if (finalConfig.onTabChange) {
|
|
489
|
-
const firstTab = newTabs.length > 0 ? newTabs[0] :
|
|
406
|
+
const firstTab = newTabs.length > 0 ? newTabs[0] : void 0;
|
|
490
407
|
setTimeout(() => {
|
|
491
|
-
finalConfig.onTabChange(firstTab
|
|
408
|
+
finalConfig.onTabChange((firstTab == null ? void 0 : firstTab.id) ?? "", firstTab, newTabs);
|
|
492
409
|
}, 0);
|
|
493
410
|
}
|
|
494
411
|
return {
|
|
495
412
|
...prevState,
|
|
496
413
|
tabsList: newTabs,
|
|
497
414
|
activeKey: newActiveKey,
|
|
498
|
-
activeTabInfo: newTabs.length > 0 ? newTabs[0] :
|
|
415
|
+
activeTabInfo: newTabs.length > 0 ? newTabs[0] : void 0,
|
|
499
416
|
activeComponent: newActiveComponent
|
|
500
417
|
};
|
|
501
418
|
});
|
|
502
419
|
}, [clearCache, finalConfig]);
|
|
503
|
-
|
|
504
|
-
/**
|
|
505
|
-
* 重排标签页顺序(拖拽结束后调用)
|
|
506
|
-
* 应用固定分区约束:普通标签不可拖入固定区、固定标签不可拖出固定区
|
|
507
|
-
*/
|
|
508
420
|
const reorderTabs = useCallback((activeId, overId) => {
|
|
509
|
-
setState(prevState => {
|
|
421
|
+
setState((prevState) => {
|
|
510
422
|
const nextTabsList = reorderWithPinConstraint(prevState.tabsList, activeId, overId);
|
|
511
|
-
if (nextTabsList === prevState.tabsList)
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
tabsList: nextTabsList
|
|
515
|
-
};
|
|
423
|
+
if (nextTabsList === prevState.tabsList)
|
|
424
|
+
return prevState;
|
|
425
|
+
return { ...prevState, tabsList: nextTabsList };
|
|
516
426
|
});
|
|
517
427
|
}, []);
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
* 固定标签页:设为 pinned/不可关闭并移动到固定区末尾
|
|
521
|
-
*/
|
|
522
|
-
const pinTab = useCallback(tabId => {
|
|
523
|
-
setState(prevState => {
|
|
428
|
+
const pinTab = useCallback((tabId) => {
|
|
429
|
+
setState((prevState) => {
|
|
524
430
|
const nextTabsList = pinTabInList(prevState.tabsList, tabId);
|
|
525
|
-
if (nextTabsList === prevState.tabsList)
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
tabsList: nextTabsList,
|
|
530
|
-
activeTabInfo: nextActiveTabInfo
|
|
531
|
-
};
|
|
431
|
+
if (nextTabsList === prevState.tabsList)
|
|
432
|
+
return prevState;
|
|
433
|
+
const nextActiveTabInfo = prevState.activeKey === tabId ? nextTabsList.find((tab) => tab.id === tabId) : prevState.activeTabInfo;
|
|
434
|
+
return { ...prevState, tabsList: nextTabsList, activeTabInfo: nextActiveTabInfo };
|
|
532
435
|
});
|
|
533
436
|
}, []);
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
* 取消固定标签页:设为可关闭并移动到普通区最前
|
|
537
|
-
*/
|
|
538
|
-
const unpinTab = useCallback(tabId => {
|
|
539
|
-
setState(prevState => {
|
|
437
|
+
const unpinTab = useCallback((tabId) => {
|
|
438
|
+
setState((prevState) => {
|
|
540
439
|
const nextTabsList = unpinTabInList(prevState.tabsList, tabId);
|
|
541
|
-
if (nextTabsList === prevState.tabsList)
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
tabsList: nextTabsList,
|
|
546
|
-
activeTabInfo: nextActiveTabInfo
|
|
547
|
-
};
|
|
440
|
+
if (nextTabsList === prevState.tabsList)
|
|
441
|
+
return prevState;
|
|
442
|
+
const nextActiveTabInfo = prevState.activeKey === tabId ? nextTabsList.find((tab) => tab.id === tabId) : prevState.activeTabInfo;
|
|
443
|
+
return { ...prevState, tabsList: nextTabsList, activeTabInfo: nextActiveTabInfo };
|
|
548
444
|
});
|
|
549
445
|
}, []);
|
|
550
|
-
|
|
551
|
-
/**
|
|
552
|
-
* 重置状态
|
|
553
|
-
*/
|
|
554
446
|
const resetTabs = useCallback(() => {
|
|
555
447
|
setState({
|
|
556
448
|
tabsList: [],
|
|
557
|
-
activeKey:
|
|
449
|
+
activeKey: "",
|
|
558
450
|
newTabIndex: 0,
|
|
559
|
-
activeComponent:
|
|
451
|
+
activeComponent: ""
|
|
560
452
|
});
|
|
561
453
|
}, []);
|
|
562
|
-
|
|
563
|
-
// URL 不同步模式保留旧有的 pathname -> Tabs 初始匹配,但不写回 URL。
|
|
564
454
|
useEffect(() => {
|
|
565
|
-
if (urlSyncEnabled)
|
|
566
|
-
|
|
455
|
+
if (urlSyncEnabled)
|
|
456
|
+
return;
|
|
457
|
+
if (!dataSource || !("menus" in dataSource))
|
|
458
|
+
return;
|
|
567
459
|
const currentPath = window.location.pathname;
|
|
568
|
-
const activeTab = state.tabsList.find(tab => tab.id === state.activeKey);
|
|
569
|
-
if (activeTab && activeTab.url === currentPath)
|
|
460
|
+
const activeTab = state.tabsList.find((tab) => tab.id === state.activeKey);
|
|
461
|
+
if (activeTab && activeTab.url === currentPath)
|
|
462
|
+
return;
|
|
570
463
|
const flatMenus = flattenMenuData(dataSource.menus || []);
|
|
571
|
-
const targetMenu = flatMenus.find(item => getMenuRoute(item) === currentPath);
|
|
572
|
-
if (!targetMenu || !canOpenAsTab(targetMenu))
|
|
464
|
+
const targetMenu = flatMenus.find((item) => getMenuRoute(item) === currentPath);
|
|
465
|
+
if (!targetMenu || !canOpenAsTab(targetMenu))
|
|
466
|
+
return;
|
|
573
467
|
const existingTab = findExistingTab(state.tabsList, targetMenu);
|
|
574
468
|
if (existingTab) {
|
|
575
|
-
if (state.activeKey !== existingTab.id)
|
|
469
|
+
if (state.activeKey !== existingTab.id)
|
|
470
|
+
switchTab(existingTab.id);
|
|
576
471
|
return;
|
|
577
472
|
}
|
|
578
473
|
addTab(targetMenu);
|
|
@@ -595,4 +490,7 @@ export const useTabsState = options => {
|
|
|
595
490
|
pinTab,
|
|
596
491
|
unpinTab
|
|
597
492
|
};
|
|
598
|
-
};
|
|
493
|
+
};
|
|
494
|
+
export {
|
|
495
|
+
useTabsState
|
|
496
|
+
};
|