@bit-sun/business-component 4.2.0-alpha.6.9 → 4.2.5-per-alpha.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.
Files changed (89) hide show
  1. package/.umirc.ts +14 -10
  2. package/dist/components/Business/AddSelectBusiness/index.d.ts +3 -4
  3. package/dist/components/Business/BsLayouts/Components/AllFunc/drawContent.d.ts +1 -2
  4. package/dist/components/Business/BsLayouts/Components/ChooseStore/index.d.ts +1 -2
  5. package/dist/components/Business/BsLayouts/Components/CustomerMenu/MenuSetting/index.d.ts +1 -1
  6. package/dist/components/Business/BsLayouts/Components/CustomerMenu/MenuSetting/leftTree.d.ts +1 -1
  7. package/dist/components/Business/BsLayouts/Components/CustomerMenu/MenuSetting/rightTree.d.ts +2 -2
  8. package/dist/components/Business/BsLayouts/Components/CustomerMenu/globalMenu/DrawContent.d.ts +1 -2
  9. package/dist/components/Business/BsLayouts/Components/CustomerMenu/globalMenu/customMenuHeader.d.ts +1 -2
  10. package/dist/components/Business/BsLayouts/Components/CustomerMenu/index.d.ts +1 -1
  11. package/dist/components/Business/BsLayouts/Components/GlobalHeader/index.d.ts +1 -2
  12. package/dist/components/Business/BsLayouts/Components/RightContent/LoginModal.d.ts +1 -2
  13. package/dist/components/Business/BsLayouts/index.d.ts +1 -1
  14. package/dist/components/Business/BsSulaQueryTable/SearchItemSetting.d.ts +19 -8
  15. package/dist/components/Business/BsSulaQueryTable/index.d.ts +1 -2
  16. package/dist/components/Business/BsSulaQueryTable/setting.d.ts +9 -17
  17. package/dist/components/Business/BsSulaQueryTable/utils.d.ts +14 -15
  18. package/dist/components/Business/CommodityEntry/index.d.ts +1 -2
  19. package/dist/components/Business/CommonAlert/index.d.ts +1 -2
  20. package/dist/components/Business/CommonGuideWrapper/index.d.ts +3 -3
  21. package/dist/components/Business/DetailPageWrapper/index.d.ts +11 -12
  22. package/dist/components/Business/HomePageWrapper/index.d.ts +1 -2
  23. package/dist/components/Business/ItemPropertySelector/index.d.ts +1 -2
  24. package/dist/components/Business/JsonQueryTable/components/FieldsModifyModal.d.ts +1 -2
  25. package/dist/components/Business/JsonQueryTable/components/FieldsSettingsTable.d.ts +1 -2
  26. package/dist/components/Business/JsonQueryTable/components/Formula.d.ts +1 -2
  27. package/dist/components/Business/JsonQueryTable/components/MaintainOptions.d.ts +1 -2
  28. package/dist/components/Business/JsonQueryTable/drawer/index.d.ts +1 -2
  29. package/dist/components/Business/PropertyModal/index.d.ts +1 -2
  30. package/dist/components/Business/PropertyModal/propertyGroup.d.ts +1 -1
  31. package/dist/components/Business/SearchSelect/index.d.ts +1 -1
  32. package/dist/components/Business/StateFlow/index.d.ts +1 -2
  33. package/dist/components/Business/TreeSearchSelect/index.d.ts +1 -1
  34. package/dist/components/Business/columnSettingTable/columnSetting.d.ts +6 -6
  35. package/dist/components/Business/columnSettingTable/components/TableSumComponent.d.ts +1 -2
  36. package/dist/components/Business/columnSettingTable/index.d.ts +3 -3
  37. package/dist/components/Business/columnSettingTable/sulaSettingTable.d.ts +3 -3
  38. package/dist/components/Business/columnSettingTable/utils.d.ts +1 -2
  39. package/dist/components/Business/moreTreeTable/FixedScrollBar.d.ts +1 -1
  40. package/dist/components/Common/ParagraphCopier/index.d.ts +1 -1
  41. package/dist/components/Common/Section/index.d.ts +1 -1
  42. package/dist/components/Functional/AddSelect/index.d.ts +1 -2
  43. package/dist/components/Functional/AuthButton/index.d.ts +1 -2
  44. package/dist/components/Functional/DataImport/index.d.ts +4 -4
  45. package/dist/components/Functional/DataValidation/index.d.ts +5 -5
  46. package/dist/components/Functional/ExportFunctions/ExportIcon/index.d.ts +1 -2
  47. package/dist/components/Functional/QueryMutipleInput/index.d.ts +1 -2
  48. package/dist/components/Functional/QueryMutipleSelect/index.d.ts +1 -2
  49. package/dist/components/Functional/SearchSelect/index.d.ts +1 -1
  50. package/dist/components/Functional/SearchSelect/utils.d.ts +2 -3
  51. package/dist/components/Functional/TreeSearchSelect/index.d.ts +1 -2
  52. package/dist/components/Solution/RuleComponent/CustomPlugin/CustomSelector/CustomSelectorModal.d.ts +1 -1
  53. package/dist/components/Solution/RuleComponent/CustomPlugin/CustomSelector/index.d.ts +1 -2
  54. package/dist/components/Solution/RuleComponent/Formula.d.ts +1 -2
  55. package/dist/components/Solution/RuleComponent/InnerSelect.d.ts +1 -2
  56. package/dist/components/Solution/RuleComponent/RenderCompItem.d.ts +1 -2
  57. package/dist/components/Solution/RuleSetter/RuleInstance.d.ts +1 -2
  58. package/dist/components/Solution/RuleSetter/baseRule.d.ts +1 -1
  59. package/dist/components/Solution/RuleSetter/index.d.ts +1 -1
  60. package/dist/index.d.ts +0 -1
  61. package/dist/index.esm.js +2203 -1852
  62. package/dist/index.js +2196 -1847
  63. package/dist/plugin/TableColumnSetting/index.d.ts +5 -5
  64. package/dist/utils/TableUtils.d.ts +18 -19
  65. package/dist/utils/luckysheetLoader.d.ts +21 -0
  66. package/dist/utils/utils.d.ts +0 -41
  67. package/package.json +1 -1
  68. package/src/components/Business/BsLayouts/Components/CustomerMenu/globalMenu/DrawContent.tsx +94 -25
  69. package/src/components/Business/BsLayouts/index.tsx +235 -129
  70. package/src/components/Business/BsSulaQueryTable/SearchItemSetting.tsx +144 -4
  71. package/src/components/Business/BsSulaQueryTable/index.md +120 -0
  72. package/src/components/Business/BsSulaQueryTable/index.tsx +241 -24
  73. package/src/components/Business/BsSulaQueryTable/setting.tsx +232 -17
  74. package/src/components/Business/DetailPageWrapper/index.tsx +30 -27
  75. package/src/components/Business/HomePageWrapper/index.tsx +10 -8
  76. package/src/components/Business/SearchSelect/BusinessUtils.tsx +38 -234
  77. package/src/components/Business/columnSettingTable/index.tsx +6 -7
  78. package/src/components/Business/columnSettingTable/sulaSettingTable.tsx +22 -23
  79. package/src/components/Functional/AddSelect/index.tsx +0 -92
  80. package/src/components/Functional/DataImport/index.tsx +76 -3
  81. package/src/components/Functional/DataValidation/index.tsx +81 -3
  82. package/src/components/Functional/SearchSelect/index.tsx +2 -5
  83. package/src/components/Solution/RuleComponent/index.js +0 -1
  84. package/src/index.ts +0 -2
  85. package/src/utils/luckysheetLoader.ts +164 -0
  86. package/src/utils/utils.ts +1 -41
  87. package/dist/components/Business/SystemLog/index.d.ts +0 -78
  88. package/src/components/Business/SystemLog/index.md +0 -37
  89. package/src/components/Business/SystemLog/index.tsx +0 -87
@@ -109,12 +109,8 @@ const menuDataRender = (menuList: MenuDataItem[]): MenuDataItem[] =>
109
109
  };
110
110
  });
111
111
 
112
+ // 将全局变量移到类内部,避免内存泄漏
112
113
  let UN_LISTTEN_DRP;
113
- let routerArray = [];
114
- let authMenuPathList = [];
115
- let docsId = [];
116
- let lastTwoRouterArray = [1, 2];
117
-
118
114
  let draggerTabKeys = [];
119
115
 
120
116
  const type = 'DraggableTabNode';
@@ -165,35 +161,6 @@ const DraggableTabs = (props) => {
165
161
  const { children, changeListenRouterState } = props;
166
162
  const [order, setOrder] = useState([]);
167
163
 
168
- const moveTabNode = (dragKey, hoverKey) => {
169
- const newOrder = order.slice();
170
- React.Children.forEach(children, (c) => {
171
- if (c.key && newOrder.indexOf(c.key) === -1) {
172
- newOrder.push(c.key);
173
- }
174
- });
175
- const dragIndex = newOrder.indexOf(dragKey);
176
- const hoverIndex = newOrder.indexOf(hoverKey);
177
- newOrder.splice(dragIndex, 1);
178
- newOrder.splice(hoverIndex, 0, dragKey);
179
- changeListenRouterState(dragIndex, hoverIndex);
180
- setOrder(newOrder);
181
- };
182
-
183
- const renderTabBar = (tabBarProps, DefaultTabBar) => (
184
- <DefaultTabBar {...tabBarProps}>
185
- {(node) => (
186
- <DraggableTabNode
187
- key={node.key}
188
- index={node.key}
189
- moveNode={moveTabNode}
190
- >
191
- {node}
192
- </DraggableTabNode>
193
- )}
194
- </DefaultTabBar>
195
- );
196
-
197
164
  const tabs = [];
198
165
  React.Children.forEach(children, (c) => {
199
166
  tabs.push(c);
@@ -219,11 +186,9 @@ const DraggableTabs = (props) => {
219
186
  return ia - ib;
220
187
  });
221
188
  return (
222
- <DndProvider backend={HTML5Backend}>
223
- <Tabs renderTabBar={renderTabBar} {...props}>
224
- {orderTabs}
225
- </Tabs>
226
- </DndProvider>
189
+ <Tabs {...props}>
190
+ {orderTabs}
191
+ </Tabs>
227
192
  );
228
193
  };
229
194
 
@@ -326,17 +291,38 @@ class BasicLayout extends React.PureComponent {
326
291
  actionRef: any = createRef<{
327
292
  reload: () => void;
328
293
  }>();
294
+
295
+ // 将全局变量移到实例属性,避免多实例间的内存泄漏
296
+ private routerArray = [];
297
+ private authMenuPathList = [];
298
+ private docsId = [];
299
+ private lastTwoRouterArray = [1, 2];
300
+ private wujieEventHandler = null;
301
+ private timeoutIds = new Set(); // 管理所有setTimeout
302
+
329
303
  constructor(props) {
330
304
  super(props);
331
- authMenuPathList = getAuthMenuPathAndDocsId(props.pathToRegexp)?.menuKeys || [];
332
- docsId = getAuthMenuPathAndDocsId(props.pathToRegexp)?.docsId || [];
333
- routerArray = this.updateTree(props.route.routes, authMenuPathList);
334
- const homeRouter = routerArray.filter(
305
+ const authData = getAuthMenuPathAndDocsId(props.pathToRegexp);
306
+ this.authMenuPathList = authData?.menuKeys || [];
307
+ this.docsId = authData?.docsId || [];
308
+ this.routerArray = this.updateTree(props.route.routes, this.authMenuPathList);
309
+
310
+ // 初始化内存管理相关属性
311
+ this.timeoutIds = new Set();
312
+ this.wujieEventHandler = null;
313
+ this.cachedTabsElements = null;
314
+ this.cachedBreadcrumbNameMap = null;
315
+ this.cachedWeiqianduanProps = null;
316
+ this.cachedOperationsSlot = null;
317
+ this.lastIsSliderState = null;
318
+ const homeRouter = this.routerArray.filter(
335
319
  (itemroute) => itemroute.key === '/',
336
320
  )[0];
337
- const breadcrumbNameMap = getBreadcrumbNameMap(
321
+ // 缓存breadcrumbNameMap,避免重复创建
322
+ this.cachedBreadcrumbNameMap = this.cachedBreadcrumbNameMap || getBreadcrumbNameMap(
338
323
  memoizeOneFormatter(props.route.routes, ''),
339
324
  );
325
+ const breadcrumbNameMap = this.cachedBreadcrumbNameMap;
340
326
  const hideMenuArray = ergodicMenuRoutes(props.route.routes);
341
327
 
342
328
  this.state = {
@@ -378,6 +364,8 @@ class BasicLayout extends React.PureComponent {
378
364
  pathToRegexp,
379
365
  } = this.props;
380
366
 
367
+
368
+
381
369
  let istParent = 0;
382
370
 
383
371
  var self = this;
@@ -402,7 +390,8 @@ class BasicLayout extends React.PureComponent {
402
390
  // }
403
391
  // });
404
392
 
405
- window.$wujie?.bus.$on("main-route-change", function (appname, info) {
393
+ // 优化事件处理器,避免内存泄漏
394
+ this.wujieEventHandler = (appname, info) => {
406
395
  if (appname === itemPath) {
407
396
  if (localStorage.getItem(ENUM.BROWSER_CACHE.CHILD_APP_BACK)) {
408
397
  localStorage.removeItem(ENUM.BROWSER_CACHE.CHILD_APP_BACK);
@@ -411,14 +400,15 @@ class BasicLayout extends React.PureComponent {
411
400
  }
412
401
  istParent = 1;
413
402
  if (info.type === 'main') {
414
- let newPath = encodeUrlQuery(info.path);
415
- history.push(newPath)
403
+ const newPath = encodeUrlQuery(info.path);
404
+ history.push(newPath);
416
405
  }
417
406
  if (info.type === 'remove') {
418
407
  self.tabActions['remove'](info.path);
419
408
  }
420
409
  }
421
- });
410
+ };
411
+ window.$wujie?.bus.$on("main-route-change", this.wujieEventHandler);
422
412
 
423
413
  UN_LISTTEN_DRP = history.listen((route) => {
424
414
  // if ((window as any).__POWERED_BY_QIANKUN__) {
@@ -442,7 +432,7 @@ class BasicLayout extends React.PureComponent {
442
432
  * @param docsId 通用单据ID的数组,用于进一步筛选路由。
443
433
  * @returns 返回与当前路由匹配的第一个路由项,如果没有匹配项则返回undefined。
444
434
  */
445
- let replaceRouter = routerArray.filter((itemRoute) => {
435
+ let replaceRouter = this.routerArray.filter((itemRoute) => {
446
436
  // 单独处理通用单据预览
447
437
  if (window.top !== window && !window.__POWERED_BY_WUJIE__ && route.pathname?.includes('all-general-documents')) {
448
438
  return pathToRegexp(itemRoute.key || '').test(route.pathname);
@@ -450,7 +440,7 @@ class BasicLayout extends React.PureComponent {
450
440
  // 当路由路径包含'all-general-documents'时,按通用单据处理
451
441
  if (route.pathname?.includes('all-general-documents') && shouldUseAuth()) {
452
442
  // 检查路由路径是否匹配路由项的键,并且路径中包含至少一个通用单据ID
453
- return pathToRegexp(itemRoute.key || '').test(route.pathname) && docsId.some(item => route.pathname.includes(item));
443
+ return pathToRegexp(itemRoute.key || '').test(route.pathname) && this.docsId.some(item => route.pathname.includes(item));
454
444
  }
455
445
  // 对于不包含'all-general-documents'的路径,只检查路由路径是否匹配路由项的键
456
446
  return pathToRegexp(itemRoute.key || '').test(route.pathname);
@@ -528,8 +518,8 @@ class BasicLayout extends React.PureComponent {
528
518
  }
529
519
 
530
520
  // -------------------处理页签关闭----------------------------
531
- lastTwoRouterArray.push(route.pathname);
532
- lastTwoRouterArray.shift();
521
+ this.lastTwoRouterArray.push(route.pathname);
522
+ this.lastTwoRouterArray.shift();
533
523
 
534
524
  const {
535
525
  thisHideInMenuDoNotClose = false,
@@ -539,18 +529,18 @@ class BasicLayout extends React.PureComponent {
539
529
 
540
530
  let needRemoveKey = '';
541
531
 
542
- // lastTwoRouterArray[0] != lastTwoRouterArray[1] 该判断条件用于判断是否是tab删除操作,如果是tab页删除操作,删除的是不是最后一个打开的tab页,执行history.push会导致错误的将最后打开的那个tab页也删除掉
543
- let notSamePageFlag = lastTwoRouterArray[0] != lastTwoRouterArray[1];
532
+ // this.lastTwoRouterArray[0] != this.lastTwoRouterArray[1] 该判断条件用于判断是否是tab删除操作,如果是tab页删除操作,删除的是不是最后一个打开的tab页,执行history.push会导致错误的将最后打开的那个tab页也删除掉
533
+ const notSamePageFlag = this.lastTwoRouterArray[0] !== this.lastTwoRouterArray[1];
544
534
 
545
535
  // 满足包含closePrevPage标识则直接删除上一页
546
536
  if (closePrevPage) {
547
- needRemoveKey = lastTwoRouterArray[0] && typeof lastTwoRouterArray[0] === 'string' && notSamePageFlag ? lastTwoRouterArray[0] : '';
537
+ needRemoveKey = this.lastTwoRouterArray[0] && typeof this.lastTwoRouterArray[0] === 'string' && notSamePageFlag ? this.lastTwoRouterArray[0] : '';
548
538
  } else {
549
539
  // 满足非tabclick或者menuClick的hideInMenu类型菜单自动关闭
550
540
  const shouldClosePrev = (!localStorage.getItem('isTabChange') && !localStorage.getItem('isMenuClick'));
551
- const needRemoveKeyArray = lastTwoRouterArray[0] && typeof lastTwoRouterArray[0] === 'string' && shouldClosePrev ?
541
+ const needRemoveKeyArray = this.lastTwoRouterArray[0] && typeof this.lastTwoRouterArray[0] === 'string' && shouldClosePrev ?
552
542
  hideMenuArray.filter((itemRoute) =>
553
- pathToRegexp(itemRoute.path || '').test(lastTwoRouterArray[0]),
543
+ pathToRegexp(itemRoute.path || '').test(this.lastTwoRouterArray[0]),
554
544
  ) : [];
555
545
  needRemoveKey = needRemoveKeyArray.length && notSamePageFlag && !thisHideInMenuDoNotClose ? needRemoveKeyArray[0] : '';
556
546
  }
@@ -558,19 +548,22 @@ class BasicLayout extends React.PureComponent {
558
548
  if (needRemoveKey) {
559
549
  newListenRouterState = newListenRouterState.filter((item) => {
560
550
  const [pathname] = item.key ? item.key.split('?') : [];
561
- return pathname && pathname !== lastTwoRouterArray[0];
551
+ return pathname && pathname !== this.lastTwoRouterArray[0];
562
552
  });
563
553
  newListenRouterKey = newListenRouterKey.filter((item) => {
564
554
  const [pathname] = item ? item.split('?') : [];
565
- return pathname && pathname !== lastTwoRouterArray[0];
555
+ return pathname && pathname !== this.lastTwoRouterArray[0];
566
556
  });
567
557
  }
568
558
 
569
- setTimeout(() => {
559
+ // 优化setTimeout管理,避免内存泄漏
560
+ const timeoutId = setTimeout(() => {
570
561
  // 处理页面刷新两面
571
562
  localStorage.removeItem('isTabChange');
572
563
  localStorage.removeItem('isMenuClick');
564
+ this.timeoutIds.delete(timeoutId);
573
565
  }, 0);
566
+ this.timeoutIds.add(timeoutId);
574
567
 
575
568
  // -------------------处理页签关闭 end----------------------------
576
569
 
@@ -607,8 +600,34 @@ class BasicLayout extends React.PureComponent {
607
600
  }
608
601
 
609
602
  componentWillUnmount() {
610
- // eslint-disable-next-line no-unused-expressions
611
- UN_LISTTEN_DRP && UN_LISTTEN_DRP();
603
+ // 清理路由监听器
604
+ if (UN_LISTTEN_DRP) {
605
+ UN_LISTTEN_DRP();
606
+ UN_LISTTEN_DRP = null;
607
+ }
608
+
609
+ // 清理wujie事件监听器
610
+ if (this.wujieEventHandler && window.$wujie?.bus) {
611
+ window.$wujie.bus.$off("main-route-change", this.wujieEventHandler);
612
+ this.wujieEventHandler = null;
613
+ }
614
+
615
+ // 清理所有setTimeout
616
+ this.timeoutIds.forEach(timeoutId => {
617
+ clearTimeout(timeoutId);
618
+ });
619
+ this.timeoutIds.clear();
620
+
621
+ // 清理实例属性
622
+ this.routerArray = null;
623
+ this.authMenuPathList = null;
624
+ this.docsId = null;
625
+ this.lastTwoRouterArray = null;
626
+ this.cachedTabsElements = null;
627
+ this.cachedBreadcrumbNameMap = null;
628
+ this.cachedWeiqianduanProps = null;
629
+ this.cachedOperationsSlot = null;
630
+ this.lastIsSliderState = null;
612
631
  }
613
632
 
614
633
  parseQueryString = (queryString) => {
@@ -809,8 +828,19 @@ class BasicLayout extends React.PureComponent {
809
828
  this.tabActions[action](targetKey);
810
829
  };
811
830
 
831
+
832
+
833
+
834
+
835
+
836
+
837
+
838
+
839
+
840
+
812
841
  tabActions: any = {
813
842
  remove: (targetKey: string) => {
843
+
814
844
  const { listenRouterState, activeKey, customerMatchs, listenRouterKey } =
815
845
  this.state;
816
846
 
@@ -929,49 +959,53 @@ class BasicLayout extends React.PureComponent {
929
959
  });
930
960
  }, 500);
931
961
 
962
+ // 缓存DOM元素,避免重复查询
963
+ getTabsNavElements = () => {
964
+ if (!this.cachedTabsElements || !this.cachedTabsElements.globalTabsNav) {
965
+ const globalTabsContainer = document.getElementById('globalTabs');
966
+ if (globalTabsContainer) {
967
+ this.cachedTabsElements = {
968
+ globalTabsNav: globalTabsContainer.getElementsByClassName('ant-tabs-nav-list')?.[0],
969
+ globalTabsNavWrap: globalTabsContainer.getElementsByClassName('ant-tabs-nav-wrap')?.[0]
970
+ };
971
+ }
972
+ }
973
+ return this.cachedTabsElements || {};
974
+ };
975
+
932
976
  //设置tabs标签左右滚动
933
977
  setTabNavTransLate = (num) => {
934
- let globalTabsNav = document
935
- .getElementById('globalTabs')
936
- ?.getElementsByClassName('ant-tabs-nav-list')?.[0];
937
- let globalTabsNavWrap = document
938
- .getElementById('globalTabs')
939
- ?.getElementsByClassName('ant-tabs-nav-wrap')?.[0];
940
- let wrapWidth = globalTabsNavWrap.offsetWidth; //tabsNav父节点宽度
941
- let navListWidth = globalTabsNav.offsetWidth; //tabsNav总宽度
978
+ const { globalTabsNav, globalTabsNavWrap } = this.getTabsNavElements();
979
+ if (!globalTabsNav || !globalTabsNavWrap) return;
980
+
981
+ const wrapWidth = globalTabsNavWrap.offsetWidth; //tabsNav父节点宽度
982
+ const navListWidth = globalTabsNav.offsetWidth; //tabsNav总宽度
942
983
  if (navListWidth - wrapWidth <= 0) return;
943
- let maxTransX = navListWidth - wrapWidth; // 允许移动最大宽度
944
- let transXStr = document.defaultView?.getComputedStyle(
984
+
985
+ const maxTransX = navListWidth - wrapWidth; // 允许移动最大宽度
986
+ const transXStr = document.defaultView?.getComputedStyle(
945
987
  globalTabsNav,
946
988
  null,
947
989
  ).transform;
948
- let transx = transXStr?.split(',')[4]; //当前translateX的值
990
+ const transx = transXStr?.split(',')[4]; //当前translateX的值
949
991
 
950
992
  let targetTransX = Math.abs(Number(transx)) + num;
951
993
  if (targetTransX <= 0) targetTransX = 0;
952
994
  if (targetTransX >= Number(maxTransX)) targetTransX = Number(maxTransX);
953
- globalTabsNav.style.transform = 'translateX(-' + targetTransX + 'px)';
995
+ globalTabsNav.style.transform = `translateX(-${targetTransX}px)`;
954
996
  };
955
997
 
956
998
  checkisNavSlide = () => {
957
- if (window.top != window) return;
999
+ if (window.top !== window) return;
958
1000
  //监听tabs页签总长度判断是否可点击滑动
959
- let globalTabsNav = document
960
- .getElementById('globalTabs')
961
- ?.getElementsByClassName('ant-tabs-nav-list')?.[0];
962
- let globalTabsNavWrap = document
963
- .getElementById('globalTabs')
964
- ?.getElementsByClassName('ant-tabs-nav-wrap')?.[0];
965
- let wrapWidth = globalTabsNavWrap?.offsetWidth; //tabsNav父节点宽度
966
- let navListWidth = globalTabsNav?.offsetWidth; //tabsNav总宽度
967
- if (navListWidth - wrapWidth <= 0) {
968
- this.setState({
969
- isSlider: false,
970
- });
971
- return;
972
- }
1001
+ const { globalTabsNav, globalTabsNavWrap } = this.getTabsNavElements();
1002
+ if (!globalTabsNav || !globalTabsNavWrap) return;
1003
+
1004
+ const wrapWidth = globalTabsNavWrap.offsetWidth; //tabsNav父节点宽度
1005
+ const navListWidth = globalTabsNav.offsetWidth; //tabsNav总宽度
1006
+
973
1007
  this.setState({
974
- isSlider: true,
1008
+ isSlider: navListWidth - wrapWidth > 0,
975
1009
  });
976
1010
  };
977
1011
 
@@ -1251,54 +1285,58 @@ class BasicLayout extends React.PureComponent {
1251
1285
  })
1252
1286
  .filter((item) => item) as MenuDataItem[];
1253
1287
 
1254
- let weiqianduanProps = {};
1255
- let isWeiqianduan = false;
1256
-
1257
- if (window.top != window) {
1258
- isWeiqianduan = true;
1259
- weiqianduanProps = {
1288
+ // 缓存weiqianduanProps,避免重复创建
1289
+ const isWeiqianduan = window.top !== window;
1290
+ if (!this.cachedWeiqianduanProps) {
1291
+ this.cachedWeiqianduanProps = isWeiqianduan ? {
1260
1292
  headerRender: false,
1261
1293
  footerRender: false,
1262
1294
  menuRender: false,
1263
1295
  menuHeaderRender: false,
1264
1296
  menuExtraRender: false,
1265
- };
1297
+ } : {};
1266
1298
  }
1267
-
1268
- const OperationsSlot: Record<PositionType, React.ReactNode> = {
1269
- left: (
1270
- <div className={'tab_left_operate'}>
1271
- <div
1272
- onClick={() => {
1273
- history.push({
1274
- pathname: '/',
1275
- });
1276
- }}
1277
- >
1278
- <HomeOutlined />
1299
+ const weiqianduanProps = this.cachedWeiqianduanProps;
1300
+
1301
+ // 缓存OperationsSlot,避免重复创建
1302
+ if (!this.cachedOperationsSlot || this.lastIsSliderState !== this.state.isSlider) {
1303
+ this.lastIsSliderState = this.state.isSlider;
1304
+ this.cachedOperationsSlot = {
1305
+ left: (
1306
+ <div className={'tab_left_operate'}>
1307
+ <div
1308
+ onClick={() => {
1309
+ history.push({
1310
+ pathname: '/',
1311
+ });
1312
+ }}
1313
+ >
1314
+ <HomeOutlined />
1315
+ </div>
1316
+ <div
1317
+ style={{ opacity: this.state.isSlider ? 1 : 0.5 }}
1318
+ onClick={() => {
1319
+ this.setTabNavTransLate(-100);
1320
+ }}
1321
+ >
1322
+ <DoubleLeftOutlined />
1323
+ </div>
1279
1324
  </div>
1325
+ ),
1326
+ right: (
1280
1327
  <div
1281
1328
  style={{ opacity: this.state.isSlider ? 1 : 0.5 }}
1329
+ className={'tab_right_operate'}
1282
1330
  onClick={() => {
1283
- this.setTabNavTransLate(-100);
1331
+ this.setTabNavTransLate(100);
1284
1332
  }}
1285
1333
  >
1286
- <DoubleLeftOutlined />
1334
+ <DoubleRightOutlined />
1287
1335
  </div>
1288
- </div>
1289
- ),
1290
- right: (
1291
- <div
1292
- style={{ opacity: this.state.isSlider ? 1 : 0.5 }}
1293
- className={'tab_right_operate'}
1294
- onClick={() => {
1295
- this.setTabNavTransLate(100);
1296
- }}
1297
- >
1298
- <DoubleRightOutlined />
1299
- </div>
1300
- ),
1301
- };
1336
+ ),
1337
+ };
1338
+ }
1339
+ const OperationsSlot = this.cachedOperationsSlot;
1302
1340
 
1303
1341
  return (
1304
1342
  <ProLayout
@@ -1473,7 +1511,7 @@ class BasicLayout extends React.PureComponent {
1473
1511
  {...weiqianduanProps}
1474
1512
  >
1475
1513
  <div id="globalTabsContent" className="globalTabs">
1476
- <DraggableTabs
1514
+ <Tabs
1477
1515
  activeKey={activeKey}
1478
1516
  id="globalTabs"
1479
1517
  onChange={this.onChange}
@@ -1496,8 +1534,15 @@ class BasicLayout extends React.PureComponent {
1496
1534
  tabBarGutter={8}
1497
1535
  onEdit={this.onEdit}
1498
1536
  tabBarExtraContent={OperationsSlot}
1537
+ destroyInactiveTabPane={true}
1499
1538
  animated={false}
1500
1539
  hideAdd
1540
+ ref={(tabsRef) => {
1541
+ if (tabsRef && !this.tabsRef) {
1542
+ this.tabsRef = tabsRef;
1543
+ console.log('[Tabs配置] destroyInactiveTabPane已设置为true,animated设置为false');
1544
+ }
1545
+ }}
1501
1546
  >
1502
1547
  {listenRouterState.map((item, index) => (
1503
1548
  <TabPane
@@ -1521,10 +1566,11 @@ class BasicLayout extends React.PureComponent {
1521
1566
  timeFormat={this.timeFormat}
1522
1567
  transparentProps={transparentProps}
1523
1568
  activeKey={activeKey}
1569
+ listenRouterState={listenRouterState}
1524
1570
  />
1525
1571
  </TabPane>
1526
1572
  ))}
1527
- </DraggableTabs>
1573
+ </Tabs>
1528
1574
  <div
1529
1575
  className="globalTabsOper"
1530
1576
  style={{
@@ -1567,17 +1613,77 @@ class BasicLayout extends React.PureComponent {
1567
1613
  class WrapperComponent extends React.Component {
1568
1614
  constructor(props) {
1569
1615
  super(props);
1616
+
1617
+ // 初始化组件状态
1618
+ this.isUnmounted = false;
1619
+ }
1620
+
1621
+ componentDidMount() {
1622
+ // 组件挂载完成
1623
+ }
1624
+
1625
+
1626
+
1627
+ componentWillUnmount() {
1628
+ // 设置卸载标志
1629
+ this.isUnmounted = true;
1630
+
1631
+ // 清理可能的DOM事件监听器
1632
+ try {
1633
+ const currentElement = document.querySelector(`#globalTabs .ant-tabs-tabpane[data-node-key="${this.props.item.key}"]`);
1634
+ if (currentElement) {
1635
+ // 移除所有可能的事件监听器
1636
+ const events = ['click', 'mousedown', 'mouseup', 'mouseover', 'mouseout', 'focus', 'blur'];
1637
+ events.forEach(eventType => {
1638
+ currentElement.removeEventListener(eventType, this.handleEvent, true);
1639
+ currentElement.removeEventListener(eventType, this.handleEvent, false);
1640
+ });
1641
+ }
1642
+
1643
+ // 强制垃圾回收提示
1644
+ if (window.gc && typeof window.gc === 'function') {
1645
+ window.gc();
1646
+ }
1647
+
1648
+ } catch (error) {
1649
+ // 清理过程中的错误处理
1650
+ }
1570
1651
  }
1652
+
1653
+ // 通用事件处理器,用于清理
1654
+ handleEvent = (event) => {
1655
+ // 空的事件处理器,仅用于清理时移除监听器
1656
+ };
1571
1657
 
1572
1658
  shouldComponentUpdate(nextProps) {
1573
- if (window.__POWERED_BY_WUJIE__ && nextProps?.item?.key?.indexOf('edit-template-template') > -1) { // 适配wujie环境主应用下渲染打印编辑器
1574
- return true
1659
+ if (window.__POWERED_BY_WUJIE__ && nextProps?.item?.key?.indexOf('edit-template-template') > -1) {
1660
+ return true;
1575
1661
  }
1662
+
1663
+ // 检测页签是否已被删除:比较当前和下一个listenRouterState
1664
+ const currentTabExists = this.props.listenRouterState?.some(tab => tab.key === this.props.item.key);
1665
+ const nextTabExists = nextProps.listenRouterState?.some(tab => tab.key === this.props.item.key);
1666
+
1667
+ // 如果页签从存在变为不存在,说明被删除了,允许更新以便正确销毁
1668
+ if (currentTabExists && !nextTabExists) {
1669
+ console.log(`页签 ${this.props.item.key} 已被删除,允许组件更新以便销毁`);
1670
+ return true;
1671
+ }
1672
+
1673
+ // 如果页签不再是活跃状态,允许更新以便正确销毁
1674
+ if (nextProps.activeKey !== nextProps.item.key && this.props.activeKey === this.props.item.key) {
1675
+ console.log(`页签 ${this.props.item.key} 不再活跃,允许组件更新`);
1676
+ return true;
1677
+ }
1678
+
1679
+ // 如果页签变为活跃状态或内容发生变化,允许更新
1576
1680
  if (nextProps.activeKey === nextProps.item.key && JSON.stringify(nextProps.item) !== JSON.stringify(this.props.item)) {
1577
1681
  return true;
1578
1682
  }
1683
+
1579
1684
  return false;
1580
1685
  }
1686
+
1581
1687
  render() {
1582
1688
  const {
1583
1689
  item,