@bit-sun/business-component 4.2.5-per-alpha.2 → 4.2.5-per-alpha.3
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/.fatherrc.ts +4 -0
- package/dist/index.esm.js +827 -353
- package/dist/index.js +827 -353
- package/package.json +5 -4
- package/src/components/Business/BsLayouts/Components/CustomerMenu/globalMenu/DrawContent.tsx +75 -45
- package/src/components/Business/BsLayouts/Components/CustomerMenu/index.tsx +13 -10
- package/src/components/Business/BsLayouts/index.tsx +142 -27
- package/src/components/Business/BsSulaQueryTable/index.tsx +588 -161
- package/src/components/Business/BsSulaQueryTable/setting.tsx +34 -24
- package/src/components/Business/HomePageWrapper/index.tsx +43 -13
- package/src/components/Business/JsonQueryTable/configTree/index.js +29 -2
- package/src/components/Functional/QueryMutipleSelect/index.tsx +33 -4
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@bit-sun/business-component",
|
|
3
|
-
"version": "4.2.5-per-alpha.
|
|
3
|
+
"version": "4.2.5-per-alpha.3",
|
|
4
4
|
"scripts": {
|
|
5
5
|
"start": "dumi dev",
|
|
6
6
|
"docs:build": "dumi build",
|
|
@@ -63,6 +63,7 @@
|
|
|
63
63
|
},
|
|
64
64
|
"devDependencies": {
|
|
65
65
|
"@ant-design/pro-layout": "7.1.3",
|
|
66
|
+
"@babel/parser": "^7.21.0",
|
|
66
67
|
"@types/js-cookie": "^3.0.6",
|
|
67
68
|
"@types/lodash": "^4.14.185",
|
|
68
69
|
"@types/react": "17.0.2",
|
|
@@ -71,18 +72,18 @@
|
|
|
71
72
|
"acorn": "^7.2.0",
|
|
72
73
|
"acorn-walk": "^7.1.1",
|
|
73
74
|
"antd": "^4.17.2",
|
|
75
|
+
"babel-plugin-transform-remove-console": "^6.9.4",
|
|
74
76
|
"bssula": "^4.2.0",
|
|
75
|
-
"umi-plugin-bssula": "^4.2.0",
|
|
76
77
|
"dumi": "^1.0.14",
|
|
77
78
|
"father-build": "^1.17.2",
|
|
78
79
|
"gh-pages": "^3.0.0",
|
|
79
80
|
"lint-staged": "^10.0.7",
|
|
81
|
+
"path-to-regexp": "^2.4.0",
|
|
80
82
|
"prettier": "^2.2.1",
|
|
81
83
|
"react-dnd": "^16.0.1",
|
|
82
84
|
"react-dnd-html5-backend": "^16.0.1",
|
|
83
85
|
"rollup-plugin-commonjs": "^10.1.0",
|
|
84
|
-
"
|
|
85
|
-
"@babel/parser": "^7.21.0"
|
|
86
|
+
"umi-plugin-bssula": "^4.2.0"
|
|
86
87
|
},
|
|
87
88
|
"publishConfig": {
|
|
88
89
|
"access": "public"
|
package/src/components/Business/BsLayouts/Components/CustomerMenu/globalMenu/DrawContent.tsx
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
// @ts-nocheck
|
|
2
|
-
import React, { useEffect, useState, useLayoutEffect, useImperativeHandle, useCallback, useRef } from 'react';
|
|
2
|
+
import React, { useEffect, useState, useLayoutEffect, useImperativeHandle, useCallback, useRef, useMemo } from 'react';
|
|
3
3
|
import { List, Tooltip, Input, Button } from 'antd';
|
|
4
4
|
import { Link, formatMessage, history } from 'umi';
|
|
5
5
|
import classNames from 'classnames';
|
|
@@ -33,6 +33,7 @@ const DrawContent = ({onClose, originRoutes=[], itemPath}: any) => {
|
|
|
33
33
|
const timeoutRef = useRef<NodeJS.Timeout | null>(null);
|
|
34
34
|
const resizeHandlerRef = useRef<(() => void) | null>(null);
|
|
35
35
|
const debounceTimerRef = useRef<NodeJS.Timeout | null>(null);
|
|
36
|
+
const drawContentRef = useRef<HTMLElement | null>(null);
|
|
36
37
|
|
|
37
38
|
useEffect(() => {
|
|
38
39
|
getMenuContentHeight();
|
|
@@ -81,15 +82,20 @@ const DrawContent = ({onClose, originRoutes=[], itemPath}: any) => {
|
|
|
81
82
|
clearTimeout(debounceTimerRef.current);
|
|
82
83
|
debounceTimerRef.current = null;
|
|
83
84
|
}
|
|
85
|
+
// 清理DOM引用
|
|
86
|
+
drawContentRef.current = null;
|
|
84
87
|
};
|
|
85
88
|
}, []);
|
|
86
89
|
|
|
87
90
|
useLayoutEffect(() => {
|
|
88
91
|
timeoutRef.current = setTimeout(() => {
|
|
89
92
|
if (!isUnmountedRef.current) {
|
|
90
|
-
|
|
91
|
-
if (
|
|
92
|
-
|
|
93
|
+
// 使用缓存的DOM引用,避免重复查询
|
|
94
|
+
if (!drawContentRef.current) {
|
|
95
|
+
drawContentRef.current = document.getElementById("drawContent");
|
|
96
|
+
}
|
|
97
|
+
if (drawContentRef.current) {
|
|
98
|
+
let drawContentHeight = drawContentRef.current.scrollHeight;
|
|
93
99
|
if (drawContentHeight > rightMenuHeight) {
|
|
94
100
|
setMoreBtnShow(true);
|
|
95
101
|
}
|
|
@@ -114,36 +120,37 @@ const DrawContent = ({onClose, originRoutes=[], itemPath}: any) => {
|
|
|
114
120
|
}, []);
|
|
115
121
|
|
|
116
122
|
|
|
123
|
+
// 优化递归渲染函数,使用React.memo减少重复渲染
|
|
117
124
|
const renderChildItem = useCallback((child) => {
|
|
118
125
|
if (!child.hideInMenu && child.children) {
|
|
119
126
|
return (
|
|
120
|
-
|
|
127
|
+
<React.Fragment key={child.path || child.locale}>
|
|
121
128
|
<List.Item style={{ color: '#000', fontWeight: 'bold' }}>
|
|
122
129
|
{formatMessage({ id: `${child.locale}` })}
|
|
123
130
|
</List.Item>
|
|
124
131
|
{child.children.map((menuItem: any) => {
|
|
125
132
|
return renderChildItem(menuItem)
|
|
126
133
|
})}
|
|
127
|
-
|
|
134
|
+
</React.Fragment>
|
|
128
135
|
);
|
|
129
136
|
} else if (!child.hideInMenu && child.path) {
|
|
137
|
+
const displayText = formatMessage({ id: `${child.locale}` });
|
|
138
|
+
const truncatedText = displayText.length > 10
|
|
139
|
+
? `${formatMessage({ id: `${child.name}` }).slice(0, 10)}...`
|
|
140
|
+
: displayText;
|
|
141
|
+
|
|
130
142
|
return (
|
|
131
|
-
<List.Item style={{fontSize: '12px'}} className="allFuncOnMouserover">
|
|
143
|
+
<List.Item key={child.path} style={{fontSize: '12px'}} className="allFuncOnMouserover">
|
|
132
144
|
<Link to={child.path} onClick={(e) => {onMenuClick(e, child);}}>
|
|
133
|
-
<Tooltip
|
|
134
|
-
|
|
135
|
-
>
|
|
136
|
-
{formatMessage({ id: `${child.locale}` }).length > 10
|
|
137
|
-
? `${formatMessage({
|
|
138
|
-
id: `${child.name}`,
|
|
139
|
-
}).slice(0, 10)}...`
|
|
140
|
-
: formatMessage({ id: `${child.locale}` })}
|
|
145
|
+
<Tooltip title={displayText}>
|
|
146
|
+
{truncatedText}
|
|
141
147
|
</Tooltip>
|
|
142
|
-
<img className="allFuncOnMouseroverImg" src={right}></img>
|
|
148
|
+
<img className="allFuncOnMouseroverImg" src={right} alt="arrow"></img>
|
|
143
149
|
</Link>
|
|
144
150
|
</List.Item>
|
|
145
151
|
);
|
|
146
152
|
}
|
|
153
|
+
return null;
|
|
147
154
|
}, [onMenuClick]);
|
|
148
155
|
|
|
149
156
|
const onMenuClick = useCallback((e, item) => {
|
|
@@ -191,8 +198,54 @@ const DrawContent = ({onClose, originRoutes=[], itemPath}: any) => {
|
|
|
191
198
|
}
|
|
192
199
|
}, [debouncedSearch]);
|
|
193
200
|
|
|
201
|
+
// 优化菜单项点击处理器
|
|
202
|
+
const handleMenuItemClick = useCallback((item: any) => {
|
|
203
|
+
if (isUnmountedRef.current) return;
|
|
204
|
+
|
|
205
|
+
if (item.component) {
|
|
206
|
+
history.push({
|
|
207
|
+
pathname: item.path
|
|
208
|
+
});
|
|
209
|
+
onClose();
|
|
210
|
+
} else {
|
|
211
|
+
setCurrentOneLevel(item.path);
|
|
212
|
+
let currentDom = document.getElementById(item.path);
|
|
213
|
+
currentDom && currentDom.scrollIntoView();
|
|
214
|
+
}
|
|
215
|
+
}, [onClose]);
|
|
216
|
+
|
|
217
|
+
// 优化关闭按钮点击处理器
|
|
218
|
+
const handleCloseClick = useCallback(() => {
|
|
219
|
+
if (!isUnmountedRef.current) {
|
|
220
|
+
onClose();
|
|
221
|
+
}
|
|
222
|
+
}, [onClose]);
|
|
194
223
|
|
|
195
|
-
|
|
224
|
+
// 优化搜索结果点击处理器
|
|
225
|
+
const handleSearchResultClick = useCallback((item: any) => {
|
|
226
|
+
if (!isUnmountedRef.current) {
|
|
227
|
+
onMenuClick({stopPropagation: () => {}, preventDefault: () => {}}, item);
|
|
228
|
+
}
|
|
229
|
+
}, [onMenuClick]);
|
|
230
|
+
|
|
231
|
+
// 优化更多按钮点击处理器
|
|
232
|
+
const handleMoreButtonClick = useCallback(() => {
|
|
233
|
+
if (!isUnmountedRef.current) {
|
|
234
|
+
setShowScroll(true);
|
|
235
|
+
setMoreBtnShow(false);
|
|
236
|
+
}
|
|
237
|
+
}, []);
|
|
238
|
+
|
|
239
|
+
|
|
240
|
+
// 使用useMemo缓存searchHistoryList,避免每次渲染都重新解析localStorage
|
|
241
|
+
const searchHistoryList = useMemo(() => {
|
|
242
|
+
try {
|
|
243
|
+
return JSON.parse(localStorage.getItem(`${itemPath}_search_history`) || '[]');
|
|
244
|
+
} catch (error) {
|
|
245
|
+
console.warn('Failed to parse search history:', error);
|
|
246
|
+
return [];
|
|
247
|
+
}
|
|
248
|
+
}, [itemPath]);
|
|
196
249
|
return (
|
|
197
250
|
<div style={{height: `${drawHeight}px`}} className={'global_menu_draw_content'}>
|
|
198
251
|
<div className={'drawerWarp_left'}>
|
|
@@ -206,19 +259,9 @@ const DrawContent = ({onClose, originRoutes=[], itemPath}: any) => {
|
|
|
206
259
|
color: currentOneLevel === item.path ? '#005cff' : '#000000'
|
|
207
260
|
}}
|
|
208
261
|
onClick={(e) => {
|
|
209
|
-
if (isUnmountedRef.current) return;
|
|
210
262
|
e.stopPropagation();
|
|
211
|
-
e.preventDefault()
|
|
212
|
-
|
|
213
|
-
history.push({
|
|
214
|
-
pathname: item.path
|
|
215
|
-
})
|
|
216
|
-
onClose();
|
|
217
|
-
} else {
|
|
218
|
-
setCurrentOneLevel(item.path);
|
|
219
|
-
let currentDom = document.getElementById(item.path);
|
|
220
|
-
currentDom && currentDom.scrollIntoView();
|
|
221
|
-
}
|
|
263
|
+
e.preventDefault();
|
|
264
|
+
handleMenuItemClick(item);
|
|
222
265
|
}}
|
|
223
266
|
>
|
|
224
267
|
{item.name}
|
|
@@ -227,11 +270,7 @@ const DrawContent = ({onClose, originRoutes=[], itemPath}: any) => {
|
|
|
227
270
|
</div>
|
|
228
271
|
<div style={{flexGrow: 1, position: 'relative'}}>
|
|
229
272
|
<img
|
|
230
|
-
onClick={
|
|
231
|
-
if (!isUnmountedRef.current) {
|
|
232
|
-
onClose();
|
|
233
|
-
}
|
|
234
|
-
}}
|
|
273
|
+
onClick={handleCloseClick}
|
|
235
274
|
style={{position: 'absolute', right: '15px', top: '17px', cursor: 'pointer'}} width={24} src={closeicon} />
|
|
236
275
|
|
|
237
276
|
<div style={{ padding: '10px', marginBottom: '10px', width: '100%', }}>
|
|
@@ -259,11 +298,7 @@ const DrawContent = ({onClose, originRoutes=[], itemPath}: any) => {
|
|
|
259
298
|
(<div className={'search_menu_content'}>
|
|
260
299
|
{
|
|
261
300
|
SearhData.map((item: any) => (
|
|
262
|
-
<div onClick={(
|
|
263
|
-
if (!isUnmountedRef.current) {
|
|
264
|
-
onMenuClick(e, item);
|
|
265
|
-
}
|
|
266
|
-
}} key={item.path}>{item.name}</div>
|
|
301
|
+
<div onClick={() => handleSearchResultClick(item)} key={item.path}>{item.name}</div>
|
|
267
302
|
))
|
|
268
303
|
}
|
|
269
304
|
</div>) : (
|
|
@@ -329,12 +364,7 @@ const DrawContent = ({onClose, originRoutes=[], itemPath}: any) => {
|
|
|
329
364
|
height: '30px'
|
|
330
365
|
}}>
|
|
331
366
|
<span
|
|
332
|
-
onClick={
|
|
333
|
-
if (!isUnmountedRef.current) {
|
|
334
|
-
setShowScroll(true);
|
|
335
|
-
setMoreBtnShow(false);
|
|
336
|
-
}
|
|
337
|
-
}}
|
|
367
|
+
onClick={handleMoreButtonClick}
|
|
338
368
|
style={{color: '#8c8c8c'}}
|
|
339
369
|
>
|
|
340
370
|
<CaretDownOutlined />
|
|
@@ -4,7 +4,8 @@ import React, {
|
|
|
4
4
|
useEffect,
|
|
5
5
|
forwardRef,
|
|
6
6
|
useRef,
|
|
7
|
-
useImperativeHandle
|
|
7
|
+
useImperativeHandle,
|
|
8
|
+
useCallback
|
|
8
9
|
} from "react";
|
|
9
10
|
import { Button, Drawer, Modal, Menu } from 'antd';
|
|
10
11
|
import addIcon from '../../../../../assets/addIcon.svg';
|
|
@@ -65,19 +66,21 @@ const CustomerMenu = forwardRef(({isCollapse, handleClose, actionRef, originRout
|
|
|
65
66
|
})
|
|
66
67
|
|
|
67
68
|
|
|
68
|
-
const handleMenuClick = (item: any) => {
|
|
69
|
+
const handleMenuClick = useCallback((item: any) => {
|
|
69
70
|
if (item.children || !item.component) return;
|
|
70
|
-
setIsDrawer(
|
|
71
|
+
setIsDrawer(false);
|
|
71
72
|
history.push({
|
|
72
73
|
pathname: item.path
|
|
73
74
|
})
|
|
74
|
-
}
|
|
75
|
+
}, []);
|
|
75
76
|
|
|
76
|
-
const getMenuDom = (menuData) => {
|
|
77
|
-
return menuData.map(item => (
|
|
78
|
-
<div style={{paddingLeft: '10px'}}>
|
|
79
|
-
<div
|
|
80
|
-
|
|
77
|
+
const getMenuDom = useCallback((menuData) => {
|
|
78
|
+
return menuData.map((item, index) => (
|
|
79
|
+
<div key={`${item.path || item.name}-${index}`} style={{paddingLeft: '10px'}}>
|
|
80
|
+
<div
|
|
81
|
+
onClick={item.children || !item.component ? undefined : () => handleMenuClick(item)}
|
|
82
|
+
className={`${'menu_item'} ${item.children || !item.component ? '' : 'link_style'}`}
|
|
83
|
+
style={{fontWeight: item.children || !item.component ? 'bolder' : '400', paddingLeft: '4px', cursor: item.children || !item.component ? 'default' : 'pointer'}}>
|
|
81
84
|
{item.name}
|
|
82
85
|
</div>
|
|
83
86
|
{
|
|
@@ -85,7 +88,7 @@ const CustomerMenu = forwardRef(({isCollapse, handleClose, actionRef, originRout
|
|
|
85
88
|
}
|
|
86
89
|
</div>
|
|
87
90
|
))
|
|
88
|
-
}
|
|
91
|
+
}, [handleMenuClick]);
|
|
89
92
|
|
|
90
93
|
return (
|
|
91
94
|
<div className={'customer_menu_content'}>
|
|
@@ -618,16 +618,71 @@ class BasicLayout extends React.PureComponent {
|
|
|
618
618
|
});
|
|
619
619
|
this.timeoutIds.clear();
|
|
620
620
|
|
|
621
|
+
// 清理DOM缓存引用
|
|
622
|
+
if (this.cachedTabsElements) {
|
|
623
|
+
this.cachedTabsElements.globalTabsNav = null;
|
|
624
|
+
this.cachedTabsElements.globalTabsNavWrap = null;
|
|
625
|
+
this.cachedTabsElements = null;
|
|
626
|
+
}
|
|
627
|
+
|
|
628
|
+
// 清理ref引用
|
|
629
|
+
if (this.allFunc && this.allFunc.current) {
|
|
630
|
+
this.allFunc.current = null;
|
|
631
|
+
}
|
|
632
|
+
if (this.customerMenuRef && this.customerMenuRef.current) {
|
|
633
|
+
this.customerMenuRef.current = null;
|
|
634
|
+
}
|
|
635
|
+
if (this.actionRef && this.actionRef.current) {
|
|
636
|
+
this.actionRef.current = null;
|
|
637
|
+
}
|
|
638
|
+
|
|
621
639
|
// 清理实例属性
|
|
622
640
|
this.routerArray = null;
|
|
623
641
|
this.authMenuPathList = null;
|
|
624
642
|
this.docsId = null;
|
|
625
643
|
this.lastTwoRouterArray = null;
|
|
626
|
-
this.cachedTabsElements = null;
|
|
627
644
|
this.cachedBreadcrumbNameMap = null;
|
|
628
645
|
this.cachedWeiqianduanProps = null;
|
|
629
646
|
this.cachedOperationsSlot = null;
|
|
630
647
|
this.lastIsSliderState = null;
|
|
648
|
+
|
|
649
|
+
// 清理菜单容器的事件监听器
|
|
650
|
+
const menuContainer = document.querySelector('.sub_menu_content');
|
|
651
|
+
if (menuContainer) {
|
|
652
|
+
menuContainer.removeEventListener('click', this.handleMenuContainerClick);
|
|
653
|
+
// 清理所有菜单项的data属性和引用
|
|
654
|
+
const menuItems = menuContainer.querySelectorAll('[data-menu-item]');
|
|
655
|
+
menuItems.forEach(item => {
|
|
656
|
+
// 从WeakMap中移除引用
|
|
657
|
+
if (this.menuItemsWeakMap && this.menuItemsWeakMap.has(item)) {
|
|
658
|
+
this.menuItemsWeakMap.delete(item);
|
|
659
|
+
}
|
|
660
|
+
// 清理data属性
|
|
661
|
+
item.removeAttribute('data-menu-item');
|
|
662
|
+
item.removeAttribute('data-item-path');
|
|
663
|
+
item.removeAttribute('data-has-children');
|
|
664
|
+
});
|
|
665
|
+
}
|
|
666
|
+
|
|
667
|
+
// 清理WeakMap
|
|
668
|
+
if (this.menuItemsWeakMap) {
|
|
669
|
+
// WeakMap会自动清理,但显式清空以确保
|
|
670
|
+
this.menuItemsWeakMap = null;
|
|
671
|
+
}
|
|
672
|
+
|
|
673
|
+
// 清理方法引用,断开闭包链
|
|
674
|
+
this.handleMenuClick = null;
|
|
675
|
+
this.handleMenuContainerClick = null;
|
|
676
|
+
this.getMenuDom = null;
|
|
677
|
+
this.setShowMenu = null;
|
|
678
|
+
this.getTabsNavElements = null;
|
|
679
|
+
this.setTabNavTransLate = null;
|
|
680
|
+
this.checkisNavSlide = null;
|
|
681
|
+
|
|
682
|
+
// 强制触发垃圾回收(如果可用)
|
|
683
|
+
if (window.gc && typeof window.gc === 'function') {
|
|
684
|
+
setTimeout(() => window.gc(), 0);
|
|
685
|
+
}
|
|
631
686
|
}
|
|
632
687
|
|
|
633
688
|
parseQueryString = (queryString) => {
|
|
@@ -727,14 +782,12 @@ class BasicLayout extends React.PureComponent {
|
|
|
727
782
|
};
|
|
728
783
|
|
|
729
784
|
getDictionaryTextByValue = (dicCode: string, value: string) => {
|
|
730
|
-
let startPerformance = performance.now();
|
|
731
785
|
if (window.dicDataTextValue) {
|
|
732
786
|
const dicDataTextValue = window.dicDataTextValue;
|
|
733
787
|
let dicData = [];
|
|
734
788
|
|
|
735
789
|
dicData = dicDataTextValue[dicCode];
|
|
736
790
|
|
|
737
|
-
let endPerformance1 = performance.now();
|
|
738
791
|
|
|
739
792
|
if (value === undefined) return "-";
|
|
740
793
|
|
|
@@ -743,7 +796,6 @@ class BasicLayout extends React.PureComponent {
|
|
|
743
796
|
return value;
|
|
744
797
|
}
|
|
745
798
|
|
|
746
|
-
let endPerformance = performance.now();
|
|
747
799
|
|
|
748
800
|
return dicData[value] || value;
|
|
749
801
|
}
|
|
@@ -928,29 +980,57 @@ class BasicLayout extends React.PureComponent {
|
|
|
928
980
|
this.setShowMenu(false);
|
|
929
981
|
};
|
|
930
982
|
|
|
983
|
+
// 使用WeakMap存储菜单项引用,避免强引用
|
|
984
|
+
menuItemsWeakMap = new WeakMap();
|
|
985
|
+
|
|
986
|
+
// 容器级别的事件委托处理器
|
|
987
|
+
handleMenuContainerClick = (event) => {
|
|
988
|
+
const target = event.target.closest('[data-menu-item]');
|
|
989
|
+
if (!target) return;
|
|
990
|
+
|
|
991
|
+
const itemPath = target.getAttribute('data-item-path');
|
|
992
|
+
const hasChildren = target.getAttribute('data-has-children') === 'true';
|
|
993
|
+
|
|
994
|
+
if (!hasChildren && itemPath) {
|
|
995
|
+
// 从WeakMap中获取完整的item对象
|
|
996
|
+
const item = this.menuItemsWeakMap.get(target) || { path: itemPath };
|
|
997
|
+
this.handleMenuClick(item);
|
|
998
|
+
}
|
|
999
|
+
};
|
|
1000
|
+
|
|
931
1001
|
getMenuDom = (menuData) => {
|
|
932
|
-
return menuData.map((item) =>
|
|
933
|
-
|
|
934
|
-
|
|
935
|
-
|
|
936
|
-
|
|
937
|
-
|
|
938
|
-
|
|
939
|
-
}
|
|
940
|
-
|
|
941
|
-
|
|
942
|
-
|
|
943
|
-
|
|
944
|
-
|
|
945
|
-
|
|
946
|
-
|
|
947
|
-
|
|
1002
|
+
return menuData.map((item, index) => {
|
|
1003
|
+
const hasChildren = item.children || !item.component;
|
|
1004
|
+
|
|
1005
|
+
return (
|
|
1006
|
+
<div key={`${item.path || item.name}-${index}`}>
|
|
1007
|
+
<div
|
|
1008
|
+
data-menu-item="true"
|
|
1009
|
+
data-item-path={item.path}
|
|
1010
|
+
data-has-children={hasChildren}
|
|
1011
|
+
className={`${'menu_item'} ${hasChildren ? '' : 'link_style'}`}
|
|
1012
|
+
style={{
|
|
1013
|
+
fontWeight: hasChildren ? 'bolder' : '400',
|
|
1014
|
+
paddingLeft: '10px',
|
|
1015
|
+
marginTop: hasChildren ? '5px' : '0px',
|
|
1016
|
+
fontSize: hasChildren ? '14px' : '12px',
|
|
1017
|
+
cursor: hasChildren ? 'default' : 'pointer',
|
|
1018
|
+
}}
|
|
1019
|
+
ref={(el) => {
|
|
1020
|
+
// 使用WeakMap存储元素与item的关联
|
|
1021
|
+
if (el && !hasChildren) {
|
|
1022
|
+
this.menuItemsWeakMap.set(el, item);
|
|
1023
|
+
}
|
|
1024
|
+
}}
|
|
1025
|
+
>
|
|
1026
|
+
{item.name}
|
|
1027
|
+
</div>
|
|
1028
|
+
{!!item.children &&
|
|
1029
|
+
!!item.children.length &&
|
|
1030
|
+
this.getMenuDom(item.children)}
|
|
948
1031
|
</div>
|
|
949
|
-
|
|
950
|
-
|
|
951
|
-
this.getMenuDom(item.children)}
|
|
952
|
-
</div>
|
|
953
|
-
));
|
|
1032
|
+
);
|
|
1033
|
+
});
|
|
954
1034
|
};
|
|
955
1035
|
|
|
956
1036
|
setShowMenu = debounce((isShow) => {
|
|
@@ -1534,7 +1614,7 @@ class BasicLayout extends React.PureComponent {
|
|
|
1534
1614
|
tabBarGutter={8}
|
|
1535
1615
|
onEdit={this.onEdit}
|
|
1536
1616
|
tabBarExtraContent={OperationsSlot}
|
|
1537
|
-
destroyInactiveTabPane={true}
|
|
1617
|
+
// destroyInactiveTabPane={true}
|
|
1538
1618
|
animated={false}
|
|
1539
1619
|
hideAdd
|
|
1540
1620
|
ref={(tabsRef) => {
|
|
@@ -1599,6 +1679,7 @@ class BasicLayout extends React.PureComponent {
|
|
|
1599
1679
|
onMouseLeave={() => {
|
|
1600
1680
|
this.setShowMenu(false);
|
|
1601
1681
|
}}
|
|
1682
|
+
onClick={this.handleMenuContainerClick}
|
|
1602
1683
|
className={'sub_menu_content'}
|
|
1603
1684
|
style={{ display: showSubMenu && !collapse ? 'block' : 'none' }}
|
|
1604
1685
|
>
|
|
@@ -1630,7 +1711,7 @@ class WrapperComponent extends React.Component {
|
|
|
1630
1711
|
|
|
1631
1712
|
// 清理可能的DOM事件监听器
|
|
1632
1713
|
try {
|
|
1633
|
-
const currentElement = document.
|
|
1714
|
+
const currentElement = document.getElementById('globalTabs-panel-' + this.props.item.key);
|
|
1634
1715
|
if (currentElement) {
|
|
1635
1716
|
// 移除所有可能的事件监听器
|
|
1636
1717
|
const events = ['click', 'mousedown', 'mouseup', 'mouseover', 'mouseout', 'focus', 'blur'];
|
|
@@ -1638,6 +1719,35 @@ class WrapperComponent extends React.Component {
|
|
|
1638
1719
|
currentElement.removeEventListener(eventType, this.handleEvent, true);
|
|
1639
1720
|
currentElement.removeEventListener(eventType, this.handleEvent, false);
|
|
1640
1721
|
});
|
|
1722
|
+
|
|
1723
|
+
// 清理拖拽相关的事件监听器
|
|
1724
|
+
const dragEvents = ['dragstart', 'dragend', 'dragover', 'dragenter', 'dragleave', 'drop'];
|
|
1725
|
+
dragEvents.forEach(eventType => {
|
|
1726
|
+
currentElement.removeEventListener(eventType, this.handleDragEvent, true);
|
|
1727
|
+
currentElement.removeEventListener(eventType, this.handleDragEvent, false);
|
|
1728
|
+
});
|
|
1729
|
+
|
|
1730
|
+
// 清理react-dnd相关的属性和状态
|
|
1731
|
+
if (currentElement._reactInternalFiber) {
|
|
1732
|
+
delete currentElement._reactInternalFiber;
|
|
1733
|
+
}
|
|
1734
|
+
if (currentElement._reactInternalInstance) {
|
|
1735
|
+
delete currentElement._reactInternalInstance;
|
|
1736
|
+
}
|
|
1737
|
+
|
|
1738
|
+
// 清理可能的拖拽状态数据
|
|
1739
|
+
const dragStateKeys = Object.keys(currentElement).filter(key =>
|
|
1740
|
+
key.includes('drag') || key.includes('drop') || key.includes('dnd')
|
|
1741
|
+
);
|
|
1742
|
+
dragStateKeys.forEach(key => {
|
|
1743
|
+
try {
|
|
1744
|
+
delete currentElement[key];
|
|
1745
|
+
} catch (e) {
|
|
1746
|
+
// 忽略删除失败的情况
|
|
1747
|
+
}
|
|
1748
|
+
});
|
|
1749
|
+
|
|
1750
|
+
currentElement = null;
|
|
1641
1751
|
}
|
|
1642
1752
|
|
|
1643
1753
|
// 强制垃圾回收提示
|
|
@@ -1654,6 +1764,11 @@ class WrapperComponent extends React.Component {
|
|
|
1654
1764
|
handleEvent = (event) => {
|
|
1655
1765
|
// 空的事件处理器,仅用于清理时移除监听器
|
|
1656
1766
|
};
|
|
1767
|
+
|
|
1768
|
+
// 拖拽事件处理器,用于清理
|
|
1769
|
+
handleDragEvent = (event) => {
|
|
1770
|
+
// 空的拖拽事件处理器,仅用于清理时移除监听器
|
|
1771
|
+
};
|
|
1657
1772
|
|
|
1658
1773
|
shouldComponentUpdate(nextProps) {
|
|
1659
1774
|
if (window.__POWERED_BY_WUJIE__ && nextProps?.item?.key?.indexOf('edit-template-template') > -1) {
|