@bit-sun/business-component 4.2.5-per-alpha.1 → 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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@bit-sun/business-component",
3
- "version": "4.2.5-per-alpha.1",
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
- "path-to-regexp": "^2.4.0",
85
- "@babel/parser": "^7.21.0"
86
+ "umi-plugin-bssula": "^4.2.0"
86
87
  },
87
88
  "publishConfig": {
88
89
  "access": "public"
@@ -1,5 +1,5 @@
1
1
  // @ts-nocheck
2
- import React, { useEffect, useState, useLayoutEffect, useImperativeHandle } 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';
@@ -27,6 +27,13 @@ const DrawContent = ({onClose, originRoutes=[], itemPath}: any) => {
27
27
 
28
28
  const [moreBtnShow, setMoreBtnShow] = useState(false);
29
29
  const [showScroll, setShowScroll] = useState(false);
30
+
31
+ // 添加refs来跟踪组件状态和清理资源
32
+ const isUnmountedRef = useRef(false);
33
+ const timeoutRef = useRef<NodeJS.Timeout | null>(null);
34
+ const resizeHandlerRef = useRef<(() => void) | null>(null);
35
+ const debounceTimerRef = useRef<NodeJS.Timeout | null>(null);
36
+ const drawContentRef = useRef<HTMLElement | null>(null);
30
37
 
31
38
  useEffect(() => {
32
39
  getMenuContentHeight();
@@ -51,60 +58,104 @@ const DrawContent = ({onClose, originRoutes=[], itemPath}: any) => {
51
58
  setroutesData(routesDataList)
52
59
  setAuthorityMenu(authorityMenuList)
53
60
 
54
- window.onresize = () => {
55
- getMenuContentHeight();
61
+ // 创建resize处理函数并保存引用
62
+ const handleResize = () => {
63
+ if (!isUnmountedRef.current) {
64
+ getMenuContentHeight();
65
+ }
56
66
  };
67
+ resizeHandlerRef.current = handleResize;
68
+ window.addEventListener('resize', handleResize);
69
+
70
+ // 清理函数
71
+ return () => {
72
+ isUnmountedRef.current = true;
73
+ if (resizeHandlerRef.current) {
74
+ window.removeEventListener('resize', resizeHandlerRef.current);
75
+ resizeHandlerRef.current = null;
76
+ }
77
+ if (timeoutRef.current) {
78
+ clearTimeout(timeoutRef.current);
79
+ timeoutRef.current = null;
80
+ }
81
+ if (debounceTimerRef.current) {
82
+ clearTimeout(debounceTimerRef.current);
83
+ debounceTimerRef.current = null;
84
+ }
85
+ // 清理DOM引用
86
+ drawContentRef.current = null;
87
+ };
57
88
  }, []);
58
89
 
59
90
  useLayoutEffect(() => {
60
- setTimeout(() => {
61
- let drawContentHeight=document.getElementById("drawContent").scrollHeight;
62
- if (drawContentHeight > rightMenuHeight) {
63
- setMoreBtnShow(true);
91
+ timeoutRef.current = setTimeout(() => {
92
+ if (!isUnmountedRef.current) {
93
+ // 使用缓存的DOM引用,避免重复查询
94
+ if (!drawContentRef.current) {
95
+ drawContentRef.current = document.getElementById("drawContent");
96
+ }
97
+ if (drawContentRef.current) {
98
+ let drawContentHeight = drawContentRef.current.scrollHeight;
99
+ if (drawContentHeight > rightMenuHeight) {
100
+ setMoreBtnShow(true);
101
+ }
102
+ }
103
+ }
104
+ }, 0);
105
+
106
+ return () => {
107
+ if (timeoutRef.current) {
108
+ clearTimeout(timeoutRef.current);
109
+ timeoutRef.current = null;
64
110
  }
65
- }, 0)
66
- }, [])
111
+ };
112
+ }, [rightMenuHeight])
67
113
 
68
- const getMenuContentHeight = () => {
69
- let clientHeight = document.body.clientHeight;
70
- setHeight(clientHeight - 190);
71
- setDrawHeight(clientHeight - 70)
72
- }
114
+ const getMenuContentHeight = useCallback(() => {
115
+ if (!isUnmountedRef.current) {
116
+ let clientHeight = document.body.clientHeight;
117
+ setHeight(clientHeight - 190);
118
+ setDrawHeight(clientHeight - 70);
119
+ }
120
+ }, []);
73
121
 
74
122
 
75
- const renderChildItem = (child) => {
123
+ // 优化递归渲染函数,使用React.memo减少重复渲染
124
+ const renderChildItem = useCallback((child) => {
76
125
  if (!child.hideInMenu && child.children) {
77
126
  return (
78
- <>
127
+ <React.Fragment key={child.path || child.locale}>
79
128
  <List.Item style={{ color: '#000', fontWeight: 'bold' }}>
80
129
  {formatMessage({ id: `${child.locale}` })}
81
130
  </List.Item>
82
131
  {child.children.map((menuItem: any) => {
83
132
  return renderChildItem(menuItem)
84
133
  })}
85
- </>
134
+ </React.Fragment>
86
135
  );
87
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
+
88
142
  return (
89
- <List.Item style={{fontSize: '12px'}} className="allFuncOnMouserover">
143
+ <List.Item key={child.path} style={{fontSize: '12px'}} className="allFuncOnMouserover">
90
144
  <Link to={child.path} onClick={(e) => {onMenuClick(e, child);}}>
91
- <Tooltip
92
- title={formatMessage({ id: `${child.locale}` })}
93
- >
94
- {formatMessage({ id: `${child.locale}` }).length > 10
95
- ? `${formatMessage({
96
- id: `${child.name}`,
97
- }).slice(0, 10)}...`
98
- : formatMessage({ id: `${child.locale}` })}
145
+ <Tooltip title={displayText}>
146
+ {truncatedText}
99
147
  </Tooltip>
100
- <img className="allFuncOnMouseroverImg" src={right}></img>
148
+ <img className="allFuncOnMouseroverImg" src={right} alt="arrow"></img>
101
149
  </Link>
102
150
  </List.Item>
103
151
  );
104
152
  }
105
- }
153
+ return null;
154
+ }, [onMenuClick]);
106
155
 
107
- const onMenuClick = (e, item) => {
156
+ const onMenuClick = useCallback((e, item) => {
157
+ if (isUnmountedRef.current) return;
158
+
108
159
  e.stopPropagation();
109
160
  e.preventDefault();
110
161
  let searchHistory = JSON.parse(localStorage.getItem(`${itemPath}_search_history`) || '[]');
@@ -127,10 +178,74 @@ const DrawContent = ({onClose, originRoutes=[], itemPath}: any) => {
127
178
  pathname: item.path
128
179
  })
129
180
  onClose();
130
- };
181
+ }, [itemPath, onClose]);
182
+
183
+ // 创建debounce搜索函数
184
+ const debouncedSearch = useCallback((value: string) => {
185
+ if (debounceTimerRef.current) {
186
+ clearTimeout(debounceTimerRef.current);
187
+ }
188
+ debounceTimerRef.current = setTimeout(() => {
189
+ if (!isUnmountedRef.current) {
190
+ searchMenuData(authorityMenu, value, setSearchMenuData);
191
+ }
192
+ }, 600);
193
+ }, [authorityMenu]);
194
+
195
+ const handleSearchChange = useCallback((e: any) => {
196
+ if (!isUnmountedRef.current) {
197
+ debouncedSearch(e.target.value);
198
+ }
199
+ }, [debouncedSearch]);
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]);
223
+
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
+ }, []);
131
238
 
132
239
 
133
- let searchHistoryList = JSON.parse(localStorage.getItem(`${itemPath}_search_history`) || '[]');
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]);
134
249
  return (
135
250
  <div style={{height: `${drawHeight}px`}} className={'global_menu_draw_content'}>
136
251
  <div className={'drawerWarp_left'}>
@@ -145,17 +260,8 @@ const DrawContent = ({onClose, originRoutes=[], itemPath}: any) => {
145
260
  }}
146
261
  onClick={(e) => {
147
262
  e.stopPropagation();
148
- e.preventDefault()
149
- if (item.component) {
150
- history.push({
151
- pathname: item.path
152
- })
153
- onClose();
154
- } else {
155
- setCurrentOneLevel(item.path);
156
- let currentDom = document.getElementById(item.path);
157
- currentDom && currentDom.scrollIntoView();
158
- }
263
+ e.preventDefault();
264
+ handleMenuItemClick(item);
159
265
  }}
160
266
  >
161
267
  {item.name}
@@ -164,7 +270,7 @@ const DrawContent = ({onClose, originRoutes=[], itemPath}: any) => {
164
270
  </div>
165
271
  <div style={{flexGrow: 1, position: 'relative'}}>
166
272
  <img
167
- onClick={() => {onClose()}}
273
+ onClick={handleCloseClick}
168
274
  style={{position: 'absolute', right: '15px', top: '17px', cursor: 'pointer'}} width={24} src={closeicon} />
169
275
 
170
276
  <div style={{ padding: '10px', marginBottom: '10px', width: '100%', }}>
@@ -173,9 +279,7 @@ const DrawContent = ({onClose, originRoutes=[], itemPath}: any) => {
173
279
  placeholder="请输入关键词"
174
280
  allowClear
175
281
  prefix={<SearchOutlined />}
176
- onChange={debounce((e: any) => {
177
- searchMenuData(authorityMenu, e.target.value, setSearchMenuData);
178
- }, 600)}
282
+ onChange={handleSearchChange}
179
283
  />
180
284
  <div style={{marginTop: '10px'}}>
181
285
  <span style={{ color: '#8c8c8c', opacity: '0.6' }}>最近访问:&nbsp;&nbsp;&nbsp;</span>
@@ -194,9 +298,7 @@ const DrawContent = ({onClose, originRoutes=[], itemPath}: any) => {
194
298
  (<div className={'search_menu_content'}>
195
299
  {
196
300
  SearhData.map((item: any) => (
197
- <div onClick={(e) => {
198
- onMenuClick(e, item);
199
- }} key={item.path}>{item.name}</div>
301
+ <div onClick={() => handleSearchResultClick(item)} key={item.path}>{item.name}</div>
200
302
  ))
201
303
  }
202
304
  </div>) : (
@@ -262,10 +364,7 @@ const DrawContent = ({onClose, originRoutes=[], itemPath}: any) => {
262
364
  height: '30px'
263
365
  }}>
264
366
  <span
265
- onClick={() => {
266
- setShowScroll(true);
267
- setMoreBtnShow(false);
268
- }}
367
+ onClick={handleMoreButtonClick}
269
368
  style={{color: '#8c8c8c'}}
270
369
  >
271
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(!isDrawer);
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 onClick={()=> {handleMenuClick(item)}} className={`${'menu_item'} ${item.children || !item.component ? '' : 'link_style'}`}
80
- style={{fontWeight: item.children || !item.component ? 'bolder' : '400', paddingLeft: '4px'}}>
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'}>