@zat-design/sisyphus-react 4.5.10-beta.1 → 4.5.10-beta.2
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 +290 -408
- package/es/ProLayout/components/TabsManager/hooks/useTabsUrlSync.js +132 -95
- package/es/ProLayout/components/TabsManager/index.js +406 -390
- 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.js +127 -184
- package/es/ProLayout/components/index.js +8 -3
- package/es/ProLayout/index.js +171 -229
- 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,247 @@
|
|
|
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
|
+
findExistingTab,
|
|
17
|
+
normalizeTabUrl,
|
|
18
|
+
isSafeExternalUrl,
|
|
19
|
+
isSafeHttpUrl,
|
|
20
|
+
resolveTabMenuItem,
|
|
21
|
+
derivePinned,
|
|
22
|
+
getPinnedBoundary,
|
|
23
|
+
pinTab as pinTabInList,
|
|
24
|
+
unpinTab as unpinTabInList,
|
|
25
|
+
reorderWithPinConstraint
|
|
26
|
+
} from "../utils";
|
|
27
|
+
const useTabsState = (options) => {
|
|
28
|
+
const { initialState = {}, config, dataSource, cacheEnabled = true } = options;
|
|
29
|
+
const finalConfig = { ...DEFAULT_TABS_CONFIG, ...config };
|
|
30
|
+
const urlSyncEnabled = finalConfig.urlSync === true || typeof finalConfig.urlSync === "object" && finalConfig.urlSync !== null;
|
|
27
31
|
const [state, setState] = useState(() => ({
|
|
28
32
|
tabsList: [],
|
|
29
|
-
activeKey:
|
|
30
|
-
activeTabInfo:
|
|
33
|
+
activeKey: "",
|
|
34
|
+
activeTabInfo: void 0,
|
|
31
35
|
newTabIndex: 0,
|
|
32
|
-
activeComponent:
|
|
36
|
+
activeComponent: "",
|
|
33
37
|
...initialState
|
|
34
38
|
}));
|
|
35
|
-
|
|
36
|
-
// 缓存管理
|
|
37
|
-
const {
|
|
38
|
-
saveToCache,
|
|
39
|
-
restoreFromCache,
|
|
40
|
-
clearCache
|
|
41
|
-
} = useTabsCache({
|
|
39
|
+
const { saveToCache, restoreFromCache, clearCache } = useTabsCache({
|
|
42
40
|
cacheKey: finalConfig.cacheKey,
|
|
43
41
|
storage: finalConfig.storage,
|
|
44
42
|
enabled: cacheEnabled
|
|
45
43
|
});
|
|
46
|
-
|
|
47
|
-
// 初始化标记,确保只在初始化后保存缓存
|
|
48
44
|
const [isInitialized, setIsInitialized] = useState(false);
|
|
49
|
-
|
|
50
|
-
// 从缓存恢复状态
|
|
51
45
|
const hasRestoredCacheRef = useRef(false);
|
|
52
46
|
useEffect(() => {
|
|
53
|
-
|
|
47
|
+
var _a, _b;
|
|
48
|
+
if (hasRestoredCacheRef.current)
|
|
49
|
+
return;
|
|
54
50
|
hasRestoredCacheRef.current = true;
|
|
55
51
|
const cachedState = restoreFromCache();
|
|
56
52
|
if (cachedState && cachedState.tabsList && cachedState.tabsList.length > 0) {
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
...cachedState
|
|
60
|
-
};
|
|
61
|
-
if ('activeTab' in restoredState && !restoredState.activeTabInfo) {
|
|
53
|
+
const restoredState = { ...cachedState };
|
|
54
|
+
if ("activeTab" in restoredState && !restoredState.activeTabInfo) {
|
|
62
55
|
restoredState.activeTabInfo = restoredState.activeTab;
|
|
63
56
|
delete restoredState.activeTab;
|
|
64
57
|
}
|
|
65
|
-
|
|
66
|
-
// 兼容旧缓存:Ant Tabs 的 onChange 始终返回字符串 key;旧版本可能保存数字 id,
|
|
67
|
-
// 若不归一化,严格比较会导致恢复后的标签无法切换。
|
|
68
|
-
restoredState.tabsList = restoredState.tabsList.map(tab => ({
|
|
58
|
+
restoredState.tabsList = restoredState.tabsList.map((tab) => ({
|
|
69
59
|
...tab,
|
|
70
60
|
id: String(tab.id),
|
|
71
|
-
pinned: tab.pinned ===
|
|
61
|
+
pinned: tab.pinned === void 0 ? derivePinned(tab) : tab.pinned
|
|
72
62
|
}));
|
|
73
|
-
restoredState.activeKey = restoredState.activeKey ===
|
|
63
|
+
restoredState.activeKey = restoredState.activeKey === void 0 || restoredState.activeKey === null ? "" : String(restoredState.activeKey);
|
|
74
64
|
if (urlSyncEnabled) {
|
|
75
|
-
const retainedTabByUrl = new Map();
|
|
76
|
-
const retainedIdByOriginalId = new Map();
|
|
77
|
-
restoredState.tabsList.forEach(tab => {
|
|
65
|
+
const retainedTabByUrl = /* @__PURE__ */ new Map();
|
|
66
|
+
const retainedIdByOriginalId = /* @__PURE__ */ new Map();
|
|
67
|
+
restoredState.tabsList.forEach((tab) => {
|
|
78
68
|
const normalizedUrl = normalizeTabUrl(tab.url);
|
|
79
|
-
if (!normalizedUrl)
|
|
69
|
+
if (!normalizedUrl)
|
|
70
|
+
return;
|
|
80
71
|
const retainedTab = retainedTabByUrl.get(normalizedUrl);
|
|
81
72
|
if (retainedTab) {
|
|
82
73
|
retainedIdByOriginalId.set(tab.id, retainedTab.id);
|
|
83
74
|
return;
|
|
84
75
|
}
|
|
85
|
-
const normalizedTab = {
|
|
86
|
-
...tab,
|
|
87
|
-
url: normalizedUrl
|
|
88
|
-
};
|
|
76
|
+
const normalizedTab = { ...tab, url: normalizedUrl };
|
|
89
77
|
retainedTabByUrl.set(normalizedUrl, normalizedTab);
|
|
90
78
|
retainedIdByOriginalId.set(tab.id, normalizedTab.id);
|
|
91
79
|
});
|
|
92
80
|
restoredState.tabsList = Array.from(retainedTabByUrl.values());
|
|
93
|
-
restoredState.activeKey = retainedIdByOriginalId.get(restoredState.activeKey) || restoredState.tabsList[0]
|
|
81
|
+
restoredState.activeKey = retainedIdByOriginalId.get(restoredState.activeKey) || ((_a = restoredState.tabsList[0]) == null ? void 0 : _a.id) || "";
|
|
94
82
|
}
|
|
95
|
-
restoredState.activeTabInfo = restoredState.tabsList.find(
|
|
96
|
-
|
|
83
|
+
restoredState.activeTabInfo = restoredState.tabsList.find(
|
|
84
|
+
(tab) => tab.id === restoredState.activeKey
|
|
85
|
+
);
|
|
86
|
+
restoredState.activeComponent = restoredState.activeTabInfo ? ((_b = restoredState.activeTabInfo.menuItem) == null ? void 0 : _b.code) || restoredState.activeTabInfo.id : "";
|
|
97
87
|
setState(restoredState);
|
|
98
88
|
}
|
|
99
89
|
setIsInitialized(true);
|
|
100
90
|
}, [restoreFromCache, urlSyncEnabled]);
|
|
101
|
-
const lastActiveKeyRef = useRef(
|
|
91
|
+
const lastActiveKeyRef = useRef("");
|
|
102
92
|
const shouldSkipSaveRef = useRef(false);
|
|
103
93
|
const initialTabsAppliedRef = useRef(false);
|
|
104
|
-
|
|
105
|
-
// 保存状态到缓存
|
|
106
94
|
useEffect(() => {
|
|
107
|
-
if (!isInitialized)
|
|
108
|
-
|
|
109
|
-
// 如果标记了跳过保存(清空缓存后),则跳过本次保存
|
|
95
|
+
if (!isInitialized)
|
|
96
|
+
return;
|
|
110
97
|
if (shouldSkipSaveRef.current) {
|
|
111
98
|
shouldSkipSaveRef.current = false;
|
|
112
99
|
return;
|
|
113
100
|
}
|
|
114
|
-
|
|
115
|
-
// 处理 onTabChange 调用 - 支持空状态和正常切换
|
|
116
101
|
if (finalConfig.onTabChange && lastActiveKeyRef.current !== state.activeKey) {
|
|
117
102
|
lastActiveKeyRef.current = state.activeKey;
|
|
118
103
|
if (state.activeKey) {
|
|
119
|
-
|
|
120
|
-
const activeTab = state.tabsList.find(tab => tab.id === state.activeKey);
|
|
104
|
+
const activeTab = state.tabsList.find((tab) => tab.id === state.activeKey);
|
|
121
105
|
if (activeTab) {
|
|
122
106
|
finalConfig.onTabChange(state.activeKey, activeTab, state.tabsList);
|
|
123
107
|
}
|
|
124
108
|
} else {
|
|
125
|
-
|
|
126
|
-
finalConfig.onTabChange('', undefined, state.tabsList);
|
|
109
|
+
finalConfig.onTabChange("", void 0, state.tabsList);
|
|
127
110
|
}
|
|
128
111
|
}
|
|
129
|
-
|
|
130
|
-
// 如果 tabsList 为空且 activeKey 为空,说明是清空状态,不保存缓存
|
|
131
112
|
if (state.tabsList.length === 0 && !state.activeKey) {
|
|
132
113
|
return;
|
|
133
114
|
}
|
|
134
|
-
|
|
135
|
-
// 保存状态到缓存
|
|
136
115
|
saveToCache(state);
|
|
137
116
|
}, [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;
|
|
117
|
+
const canAddTab = useCallback(
|
|
118
|
+
(menuItem, options2) => {
|
|
119
|
+
const { forceNew = false } = options2 || {};
|
|
120
|
+
if (!canOpenAsTab(menuItem)) {
|
|
121
|
+
return false;
|
|
165
122
|
}
|
|
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
123
|
if (shouldOpenExternal(menuItem)) {
|
|
187
|
-
|
|
188
|
-
if (!urlSyncEnabled || isSafeHttpUrl(externalUrl)) {
|
|
189
|
-
handleExternalOpen(menuItem, urlSyncEnabled);
|
|
190
|
-
}
|
|
191
|
-
return prevState;
|
|
124
|
+
return false;
|
|
192
125
|
}
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
126
|
+
if (urlSyncEnabled || !forceNew) {
|
|
127
|
+
const existingTab = findExistingTab(state.tabsList, menuItem, {
|
|
128
|
+
urlSync: urlSyncEnabled
|
|
129
|
+
});
|
|
130
|
+
if (existingTab) {
|
|
131
|
+
return true;
|
|
198
132
|
}
|
|
199
|
-
return prevState;
|
|
200
133
|
}
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
}
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
134
|
+
if (checkTabLimit(state.tabsList, finalConfig.max)) {
|
|
135
|
+
return false;
|
|
136
|
+
}
|
|
137
|
+
return true;
|
|
138
|
+
},
|
|
139
|
+
[state.tabsList, finalConfig, urlSyncEnabled]
|
|
140
|
+
);
|
|
141
|
+
const addTab = useCallback(
|
|
142
|
+
(menuItem, options2) => {
|
|
143
|
+
const { forceNew = false, silent = false } = options2 || {};
|
|
144
|
+
setState((prevState) => {
|
|
145
|
+
var _a;
|
|
146
|
+
if (!canOpenAsTab(menuItem))
|
|
147
|
+
return prevState;
|
|
148
|
+
if (shouldOpenExternal(menuItem)) {
|
|
149
|
+
const externalUrl = getMenuRoute(menuItem);
|
|
150
|
+
if (!urlSyncEnabled || isSafeHttpUrl(externalUrl)) {
|
|
151
|
+
handleExternalOpen(menuItem, urlSyncEnabled);
|
|
152
|
+
}
|
|
153
|
+
return prevState;
|
|
154
|
+
}
|
|
155
|
+
const rawUrl = getMenuRoute(menuItem);
|
|
156
|
+
const normalizedUrl = urlSyncEnabled ? normalizeTabUrl(rawUrl) : void 0;
|
|
157
|
+
if (urlSyncEnabled && rawUrl && !normalizedUrl) {
|
|
158
|
+
if (isSafeExternalUrl(rawUrl)) {
|
|
159
|
+
handleExternalOpen(menuItem, true);
|
|
160
|
+
}
|
|
161
|
+
return prevState;
|
|
162
|
+
}
|
|
163
|
+
const resolvedMenuItem = normalizedUrl ? { ...menuItem, url: normalizedUrl, redirectUrl: void 0 } : menuItem;
|
|
164
|
+
const existingTab = urlSyncEnabled || !forceNew ? findExistingTab(prevState.tabsList, resolvedMenuItem, { urlSync: urlSyncEnabled }) : void 0;
|
|
165
|
+
if (existingTab) {
|
|
166
|
+
const correctedTab = resolvedMenuItem.closable === false && existingTab.closable !== false ? { ...existingTab, closable: false } : existingTab;
|
|
167
|
+
const updatedTabsList = correctedTab !== existingTab ? prevState.tabsList.map((t) => t.id === existingTab.id ? correctedTab : t) : prevState.tabsList;
|
|
168
|
+
return {
|
|
169
|
+
...prevState,
|
|
170
|
+
tabsList: updatedTabsList,
|
|
171
|
+
activeKey: existingTab.id,
|
|
172
|
+
activeTabInfo: correctedTab,
|
|
173
|
+
activeComponent: ((_a = existingTab.menuItem) == null ? void 0 : _a.code) || existingTab.id
|
|
174
|
+
};
|
|
175
|
+
}
|
|
176
|
+
if (checkTabLimit(prevState.tabsList, finalConfig.max)) {
|
|
177
|
+
message.info(
|
|
178
|
+
formatMessage(locale.ProLayout.tabMaxLimitMessage, { max: finalConfig.max })
|
|
179
|
+
);
|
|
180
|
+
return prevState;
|
|
181
|
+
}
|
|
182
|
+
const existingIds = prevState.tabsList.map((tab) => tab.id);
|
|
183
|
+
const tabId = generateTabId(resolvedMenuItem, existingIds);
|
|
184
|
+
const newTab = createTabFromMenu(resolvedMenuItem, prevState.newTabIndex);
|
|
185
|
+
newTab.id = tabId;
|
|
186
|
+
const pinnedBoundary = getPinnedBoundary(prevState.tabsList);
|
|
187
|
+
const nextTabsList = derivePinned(newTab) ? [
|
|
188
|
+
...prevState.tabsList.slice(0, pinnedBoundary),
|
|
189
|
+
newTab,
|
|
190
|
+
...prevState.tabsList.slice(pinnedBoundary)
|
|
191
|
+
] : [...prevState.tabsList, newTab];
|
|
192
|
+
const shouldActivate = !silent || prevState.activeKey === "";
|
|
218
193
|
return {
|
|
219
194
|
...prevState,
|
|
220
|
-
tabsList:
|
|
221
|
-
activeKey:
|
|
222
|
-
activeTabInfo:
|
|
223
|
-
|
|
195
|
+
tabsList: nextTabsList,
|
|
196
|
+
activeKey: shouldActivate ? tabId : prevState.activeKey,
|
|
197
|
+
activeTabInfo: shouldActivate ? newTab : prevState.activeTabInfo,
|
|
198
|
+
newTabIndex: prevState.newTabIndex + 1,
|
|
199
|
+
activeComponent: shouldActivate ? resolvedMenuItem.code || tabId : prevState.activeComponent
|
|
224
200
|
};
|
|
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,避免再次补签。
|
|
201
|
+
});
|
|
202
|
+
},
|
|
203
|
+
[finalConfig, urlSyncEnabled]
|
|
204
|
+
);
|
|
254
205
|
useEffect(() => {
|
|
255
206
|
const initialTabs = finalConfig.initialTabs;
|
|
256
207
|
if (!isInitialized || !cacheEnabled || initialTabsAppliedRef.current || !initialTabs || initialTabs.length === 0) {
|
|
257
208
|
return;
|
|
258
209
|
}
|
|
259
210
|
initialTabsAppliedRef.current = true;
|
|
260
|
-
if (state.tabsList.length > 0)
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
});
|
|
211
|
+
if (state.tabsList.length > 0)
|
|
212
|
+
return;
|
|
213
|
+
const sourceMenus = Array.isArray(dataSource == null ? void 0 : dataSource.menus) ? dataSource.menus : [];
|
|
214
|
+
initialTabs.forEach((params) => {
|
|
215
|
+
addTab(resolveTabMenuItem(params, sourceMenus), { silent: true });
|
|
266
216
|
});
|
|
267
|
-
}, [
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
217
|
+
}, [
|
|
218
|
+
isInitialized,
|
|
219
|
+
cacheEnabled,
|
|
220
|
+
finalConfig.initialTabs,
|
|
221
|
+
dataSource,
|
|
222
|
+
state.tabsList.length,
|
|
223
|
+
addTab
|
|
224
|
+
]);
|
|
275
225
|
const updateTab = useCallback((tabId, updates) => {
|
|
276
|
-
setState(prevState => {
|
|
277
|
-
const targetIndex = prevState.tabsList.findIndex(tab => tab.id === tabId);
|
|
278
|
-
if (targetIndex === -1)
|
|
226
|
+
setState((prevState) => {
|
|
227
|
+
const targetIndex = prevState.tabsList.findIndex((tab) => tab.id === tabId);
|
|
228
|
+
if (targetIndex === -1)
|
|
229
|
+
return prevState;
|
|
279
230
|
const target = prevState.tabsList[targetIndex];
|
|
280
231
|
const nextMenuItem = target.menuItem ? {
|
|
281
232
|
...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
|
-
})
|
|
233
|
+
...updates.name !== void 0 && { name: updates.name },
|
|
234
|
+
...updates.icon !== void 0 && { icon: updates.icon },
|
|
235
|
+
...updates.extra !== void 0 && { extra: updates.extra },
|
|
236
|
+
...updates.closable !== void 0 && { closable: updates.closable },
|
|
237
|
+
...updates.pinned !== void 0 && { pinned: updates.pinned }
|
|
297
238
|
} : target.menuItem;
|
|
298
239
|
const nextTab = {
|
|
299
240
|
...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
|
-
}),
|
|
241
|
+
...updates.name !== void 0 && { name: updates.name, title: updates.name },
|
|
242
|
+
...updates.icon !== void 0 && { icon: updates.icon },
|
|
243
|
+
...updates.closable !== void 0 && { closable: updates.closable },
|
|
244
|
+
...updates.pinned !== void 0 && { pinned: updates.pinned },
|
|
313
245
|
menuItem: nextMenuItem
|
|
314
246
|
};
|
|
315
247
|
const newTabsList = [...prevState.tabsList];
|
|
@@ -321,105 +253,89 @@ export const useTabsState = options => {
|
|
|
321
253
|
};
|
|
322
254
|
});
|
|
323
255
|
}, []);
|
|
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);
|
|
256
|
+
const removeTab = useCallback(
|
|
257
|
+
(tabId) => {
|
|
258
|
+
setState((prevState) => {
|
|
259
|
+
var _a;
|
|
260
|
+
const tabToRemove = prevState.tabsList.find((tab) => tab.id === tabId);
|
|
261
|
+
if (!tabToRemove || !tabToRemove.closable) {
|
|
262
|
+
return prevState;
|
|
364
263
|
}
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
activeKey
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
264
|
+
const newTabs = prevState.tabsList.filter((tab) => tab.id !== tabId);
|
|
265
|
+
let newActiveKey = prevState.activeKey;
|
|
266
|
+
let newActiveTabInfo = prevState.activeTabInfo;
|
|
267
|
+
let newActiveComponent = prevState.activeComponent;
|
|
268
|
+
if (prevState.activeKey === tabId && newTabs.length > 0) {
|
|
269
|
+
const currentIndex = prevState.tabsList.findIndex((tab) => tab.id === tabId);
|
|
270
|
+
const newActiveIndex = Math.min(currentIndex, newTabs.length - 1);
|
|
271
|
+
newActiveTabInfo = newTabs[newActiveIndex];
|
|
272
|
+
newActiveKey = newActiveTabInfo.id;
|
|
273
|
+
newActiveComponent = ((_a = newActiveTabInfo.menuItem) == null ? void 0 : _a.code) || newActiveTabInfo.id;
|
|
274
|
+
} else if (prevState.activeKey === tabId) {
|
|
275
|
+
newActiveKey = "";
|
|
276
|
+
newActiveTabInfo = void 0;
|
|
277
|
+
newActiveComponent = "";
|
|
278
|
+
}
|
|
279
|
+
if (newTabs.length === 0) {
|
|
280
|
+
shouldSkipSaveRef.current = true;
|
|
281
|
+
clearCache();
|
|
282
|
+
if (finalConfig.onTabChange) {
|
|
283
|
+
setTimeout(() => {
|
|
284
|
+
finalConfig.onTabChange("", void 0, []);
|
|
285
|
+
}, 0);
|
|
286
|
+
}
|
|
287
|
+
}
|
|
288
|
+
return {
|
|
289
|
+
...prevState,
|
|
290
|
+
tabsList: newTabs,
|
|
291
|
+
activeKey: newActiveKey,
|
|
292
|
+
activeTabInfo: newActiveTabInfo,
|
|
293
|
+
activeComponent: newActiveComponent
|
|
294
|
+
};
|
|
295
|
+
});
|
|
296
|
+
},
|
|
297
|
+
[clearCache, finalConfig]
|
|
298
|
+
);
|
|
299
|
+
const switchTab = useCallback((tabId) => {
|
|
300
|
+
setState((prevState) => {
|
|
301
|
+
var _a;
|
|
302
|
+
const targetTab = prevState.tabsList.find((tab) => tab.id === tabId);
|
|
303
|
+
if (!targetTab)
|
|
304
|
+
return prevState;
|
|
383
305
|
const newState = {
|
|
384
306
|
...prevState,
|
|
385
307
|
activeKey: tabId,
|
|
386
308
|
activeTabInfo: targetTab,
|
|
387
|
-
activeComponent: targetTab.menuItem
|
|
309
|
+
activeComponent: ((_a = targetTab.menuItem) == null ? void 0 : _a.code) || tabId
|
|
388
310
|
};
|
|
389
311
|
return newState;
|
|
390
312
|
});
|
|
391
313
|
}, []);
|
|
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
|
-
*/
|
|
314
|
+
const rollbackTabActivation = useCallback(
|
|
315
|
+
(previousTabId, attemptedTabId, removeAttemptedTab) => {
|
|
316
|
+
setState((prevState) => {
|
|
317
|
+
var _a;
|
|
318
|
+
if (prevState.activeKey !== attemptedTabId)
|
|
319
|
+
return prevState;
|
|
320
|
+
const nextTabsList = removeAttemptedTab ? prevState.tabsList.filter((tab) => tab.id !== attemptedTabId) : prevState.tabsList;
|
|
321
|
+
const previousTab = nextTabsList.find((tab) => tab.id === previousTabId);
|
|
322
|
+
return {
|
|
323
|
+
...prevState,
|
|
324
|
+
tabsList: nextTabsList,
|
|
325
|
+
activeKey: (previousTab == null ? void 0 : previousTab.id) || "",
|
|
326
|
+
activeTabInfo: previousTab,
|
|
327
|
+
activeComponent: previousTab ? ((_a = previousTab.menuItem) == null ? void 0 : _a.code) || previousTab.id : ""
|
|
328
|
+
};
|
|
329
|
+
});
|
|
330
|
+
},
|
|
331
|
+
[]
|
|
332
|
+
);
|
|
415
333
|
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
|
-
};
|
|
334
|
+
setState((prevState) => {
|
|
335
|
+
const targetIndex = prevState.tabsList.findIndex((tab) => tab.id === tabId);
|
|
336
|
+
if (targetIndex === -1 || prevState.tabsList[targetIndex].url === url)
|
|
337
|
+
return prevState;
|
|
338
|
+
const nextTab = { ...prevState.tabsList[targetIndex], url };
|
|
423
339
|
const nextTabsList = [...prevState.tabsList];
|
|
424
340
|
nextTabsList[targetIndex] = nextTab;
|
|
425
341
|
return {
|
|
@@ -429,150 +345,113 @@ export const useTabsState = options => {
|
|
|
429
345
|
};
|
|
430
346
|
});
|
|
431
347
|
}, []);
|
|
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);
|
|
348
|
+
const closeOtherTabs = useCallback((currentTabId) => {
|
|
349
|
+
setState((prevState) => {
|
|
350
|
+
var _a;
|
|
351
|
+
const currentTab = prevState.tabsList.find((tab) => tab.id === currentTabId);
|
|
352
|
+
if (!currentTab)
|
|
353
|
+
return prevState;
|
|
354
|
+
const newTabs = prevState.tabsList.filter((tab) => tab.id === currentTabId || !tab.closable);
|
|
443
355
|
return {
|
|
444
356
|
...prevState,
|
|
445
357
|
tabsList: newTabs,
|
|
446
358
|
activeKey: currentTabId,
|
|
447
359
|
activeTabInfo: currentTab,
|
|
448
|
-
activeComponent: currentTab.menuItem
|
|
360
|
+
activeComponent: ((_a = currentTab.menuItem) == null ? void 0 : _a.code) || currentTabId
|
|
449
361
|
};
|
|
450
362
|
});
|
|
451
363
|
}, []);
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
* 关闭右侧标签页
|
|
455
|
-
*/
|
|
456
|
-
const closeRightTabs = useCallback(currentTabId => {
|
|
457
|
-
setState(prevState => {
|
|
364
|
+
const closeRightTabs = useCallback((currentTabId) => {
|
|
365
|
+
setState((prevState) => {
|
|
458
366
|
const rightTabs = getRightTabs(prevState.tabsList, currentTabId);
|
|
459
|
-
const tabsToKeep = prevState.tabsList.filter(
|
|
367
|
+
const tabsToKeep = prevState.tabsList.filter(
|
|
368
|
+
(tab) => !rightTabs.includes(tab) || !tab.closable
|
|
369
|
+
);
|
|
460
370
|
return {
|
|
461
371
|
...prevState,
|
|
462
372
|
tabsList: tabsToKeep
|
|
463
373
|
};
|
|
464
374
|
});
|
|
465
375
|
}, []);
|
|
466
|
-
|
|
467
|
-
/**
|
|
468
|
-
* 关闭全部标签页
|
|
469
|
-
*/
|
|
470
376
|
const closeAllTabs = useCallback(() => {
|
|
471
|
-
setState(prevState => {
|
|
472
|
-
|
|
473
|
-
const newTabs = prevState.tabsList.filter(tab => !tab.closable);
|
|
474
|
-
let newActiveKey =
|
|
475
|
-
let newActiveComponent =
|
|
377
|
+
setState((prevState) => {
|
|
378
|
+
var _a;
|
|
379
|
+
const newTabs = prevState.tabsList.filter((tab) => !tab.closable);
|
|
380
|
+
let newActiveKey = "";
|
|
381
|
+
let newActiveComponent = "";
|
|
476
382
|
if (newTabs.length > 0) {
|
|
477
383
|
const firstTab = newTabs[0];
|
|
478
384
|
newActiveKey = firstTab.id;
|
|
479
|
-
newActiveComponent = firstTab.menuItem
|
|
385
|
+
newActiveComponent = ((_a = firstTab.menuItem) == null ? void 0 : _a.code) || firstTab.id;
|
|
480
386
|
}
|
|
481
|
-
|
|
482
|
-
// 关闭全部标签页时,清空缓存
|
|
483
|
-
// 标记跳过下次保存,避免清空后又被重新保存
|
|
484
387
|
shouldSkipSaveRef.current = true;
|
|
485
388
|
clearCache();
|
|
486
|
-
|
|
487
|
-
// 直接调用 onTabChange(useEffect 因 shouldSkipSaveRef 会跳过)
|
|
488
389
|
if (finalConfig.onTabChange) {
|
|
489
|
-
const firstTab = newTabs.length > 0 ? newTabs[0] :
|
|
390
|
+
const firstTab = newTabs.length > 0 ? newTabs[0] : void 0;
|
|
490
391
|
setTimeout(() => {
|
|
491
|
-
finalConfig.onTabChange(firstTab
|
|
392
|
+
finalConfig.onTabChange((firstTab == null ? void 0 : firstTab.id) ?? "", firstTab, newTabs);
|
|
492
393
|
}, 0);
|
|
493
394
|
}
|
|
494
395
|
return {
|
|
495
396
|
...prevState,
|
|
496
397
|
tabsList: newTabs,
|
|
497
398
|
activeKey: newActiveKey,
|
|
498
|
-
activeTabInfo: newTabs.length > 0 ? newTabs[0] :
|
|
399
|
+
activeTabInfo: newTabs.length > 0 ? newTabs[0] : void 0,
|
|
499
400
|
activeComponent: newActiveComponent
|
|
500
401
|
};
|
|
501
402
|
});
|
|
502
403
|
}, [clearCache, finalConfig]);
|
|
503
|
-
|
|
504
|
-
/**
|
|
505
|
-
* 重排标签页顺序(拖拽结束后调用)
|
|
506
|
-
* 应用固定分区约束:普通标签不可拖入固定区、固定标签不可拖出固定区
|
|
507
|
-
*/
|
|
508
404
|
const reorderTabs = useCallback((activeId, overId) => {
|
|
509
|
-
setState(prevState => {
|
|
405
|
+
setState((prevState) => {
|
|
510
406
|
const nextTabsList = reorderWithPinConstraint(prevState.tabsList, activeId, overId);
|
|
511
|
-
if (nextTabsList === prevState.tabsList)
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
tabsList: nextTabsList
|
|
515
|
-
};
|
|
407
|
+
if (nextTabsList === prevState.tabsList)
|
|
408
|
+
return prevState;
|
|
409
|
+
return { ...prevState, tabsList: nextTabsList };
|
|
516
410
|
});
|
|
517
411
|
}, []);
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
* 固定标签页:设为 pinned/不可关闭并移动到固定区末尾
|
|
521
|
-
*/
|
|
522
|
-
const pinTab = useCallback(tabId => {
|
|
523
|
-
setState(prevState => {
|
|
412
|
+
const pinTab = useCallback((tabId) => {
|
|
413
|
+
setState((prevState) => {
|
|
524
414
|
const nextTabsList = pinTabInList(prevState.tabsList, tabId);
|
|
525
|
-
if (nextTabsList === prevState.tabsList)
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
tabsList: nextTabsList,
|
|
530
|
-
activeTabInfo: nextActiveTabInfo
|
|
531
|
-
};
|
|
415
|
+
if (nextTabsList === prevState.tabsList)
|
|
416
|
+
return prevState;
|
|
417
|
+
const nextActiveTabInfo = prevState.activeKey === tabId ? nextTabsList.find((tab) => tab.id === tabId) : prevState.activeTabInfo;
|
|
418
|
+
return { ...prevState, tabsList: nextTabsList, activeTabInfo: nextActiveTabInfo };
|
|
532
419
|
});
|
|
533
420
|
}, []);
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
* 取消固定标签页:设为可关闭并移动到普通区最前
|
|
537
|
-
*/
|
|
538
|
-
const unpinTab = useCallback(tabId => {
|
|
539
|
-
setState(prevState => {
|
|
421
|
+
const unpinTab = useCallback((tabId) => {
|
|
422
|
+
setState((prevState) => {
|
|
540
423
|
const nextTabsList = unpinTabInList(prevState.tabsList, tabId);
|
|
541
|
-
if (nextTabsList === prevState.tabsList)
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
tabsList: nextTabsList,
|
|
546
|
-
activeTabInfo: nextActiveTabInfo
|
|
547
|
-
};
|
|
424
|
+
if (nextTabsList === prevState.tabsList)
|
|
425
|
+
return prevState;
|
|
426
|
+
const nextActiveTabInfo = prevState.activeKey === tabId ? nextTabsList.find((tab) => tab.id === tabId) : prevState.activeTabInfo;
|
|
427
|
+
return { ...prevState, tabsList: nextTabsList, activeTabInfo: nextActiveTabInfo };
|
|
548
428
|
});
|
|
549
429
|
}, []);
|
|
550
|
-
|
|
551
|
-
/**
|
|
552
|
-
* 重置状态
|
|
553
|
-
*/
|
|
554
430
|
const resetTabs = useCallback(() => {
|
|
555
431
|
setState({
|
|
556
432
|
tabsList: [],
|
|
557
|
-
activeKey:
|
|
433
|
+
activeKey: "",
|
|
558
434
|
newTabIndex: 0,
|
|
559
|
-
activeComponent:
|
|
435
|
+
activeComponent: ""
|
|
560
436
|
});
|
|
561
437
|
}, []);
|
|
562
|
-
|
|
563
|
-
// URL 不同步模式保留旧有的 pathname -> Tabs 初始匹配,但不写回 URL。
|
|
564
438
|
useEffect(() => {
|
|
565
|
-
if (urlSyncEnabled)
|
|
566
|
-
|
|
439
|
+
if (urlSyncEnabled)
|
|
440
|
+
return;
|
|
441
|
+
if (!dataSource || !("menus" in dataSource))
|
|
442
|
+
return;
|
|
567
443
|
const currentPath = window.location.pathname;
|
|
568
|
-
const activeTab = state.tabsList.find(tab => tab.id === state.activeKey);
|
|
569
|
-
if (activeTab && activeTab.url === currentPath)
|
|
444
|
+
const activeTab = state.tabsList.find((tab) => tab.id === state.activeKey);
|
|
445
|
+
if (activeTab && activeTab.url === currentPath)
|
|
446
|
+
return;
|
|
570
447
|
const flatMenus = flattenMenuData(dataSource.menus || []);
|
|
571
|
-
const targetMenu = flatMenus.find(item => getMenuRoute(item) === currentPath);
|
|
572
|
-
if (!targetMenu || !canOpenAsTab(targetMenu))
|
|
448
|
+
const targetMenu = flatMenus.find((item) => getMenuRoute(item) === currentPath);
|
|
449
|
+
if (!targetMenu || !canOpenAsTab(targetMenu))
|
|
450
|
+
return;
|
|
573
451
|
const existingTab = findExistingTab(state.tabsList, targetMenu);
|
|
574
452
|
if (existingTab) {
|
|
575
|
-
if (state.activeKey !== existingTab.id)
|
|
453
|
+
if (state.activeKey !== existingTab.id)
|
|
454
|
+
switchTab(existingTab.id);
|
|
576
455
|
return;
|
|
577
456
|
}
|
|
578
457
|
addTab(targetMenu);
|
|
@@ -595,4 +474,7 @@ export const useTabsState = options => {
|
|
|
595
474
|
pinTab,
|
|
596
475
|
unpinTab
|
|
597
476
|
};
|
|
598
|
-
};
|
|
477
|
+
};
|
|
478
|
+
export {
|
|
479
|
+
useTabsState
|
|
480
|
+
};
|