@gm-pc/react 1.13.2 → 1.13.3-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.
- package/package.json +3 -3
- package/src/component/v_browser/context/browserWindow.ts +1 -1
- package/src/component/v_browser/hooks/useWindowEffect.ts +5 -11
- package/src/component/v_browser/types.ts +7 -1
- package/src/component/v_browser/ui/index.tsx +1 -1
- package/src/component/v_browser/ui/window_wrapper.tsx +22 -22
- package/src/component/v_browser/v_browser.stories.mdx +4 -0
- package/src/component/v_browser/v_browser.tsx +31 -15
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@gm-pc/react",
|
|
3
|
-
"version": "1.13.2",
|
|
3
|
+
"version": "1.13.3-alpha.2",
|
|
4
4
|
"description": "观麦前端基础组件库",
|
|
5
5
|
"author": "liyatang <liyatang@qq.com>",
|
|
6
6
|
"homepage": "https://github.com/gmfe/gm-pc#readme",
|
|
@@ -24,7 +24,7 @@
|
|
|
24
24
|
"dependencies": {
|
|
25
25
|
"@gm-common/hooks": "^2.10.0",
|
|
26
26
|
"@gm-common/tool": "^2.10.0",
|
|
27
|
-
"@gm-pc/locales": "^1.13.2",
|
|
27
|
+
"@gm-pc/locales": "^1.13.3-alpha.2",
|
|
28
28
|
"big.js": "^6.0.1",
|
|
29
29
|
"classnames": "^2.2.5",
|
|
30
30
|
"lodash": "^4.17.19",
|
|
@@ -48,5 +48,5 @@
|
|
|
48
48
|
"react-router-dom": "^5.2.0",
|
|
49
49
|
"react-window": "^1.8.5"
|
|
50
50
|
},
|
|
51
|
-
"gitHead": "
|
|
51
|
+
"gitHead": "bdd278fe8bf983b735b760af20581ab580972632"
|
|
52
52
|
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { createContext } from 'react'
|
|
2
2
|
import { VBrowserWindow } from '../types'
|
|
3
3
|
|
|
4
|
-
const BrowserWindowContext = createContext<
|
|
4
|
+
const BrowserWindowContext = createContext<string>(undefined as any)
|
|
5
5
|
BrowserWindowContext.displayName = 'VBrowserWindowContext'
|
|
6
6
|
|
|
7
7
|
export default BrowserWindowContext
|
|
@@ -12,8 +12,8 @@ type Noop = () => void
|
|
|
12
12
|
*/
|
|
13
13
|
export default function useWindowEffect(fn: () => Noop | void, deps: Array<any>) {
|
|
14
14
|
const browser = useContext(BrowserContext)
|
|
15
|
-
|
|
16
|
-
const browserWindow =
|
|
15
|
+
const path = useContext(BrowserWindowContext)
|
|
16
|
+
const browserWindow = browser.windows.find((w) => w.path === path)!
|
|
17
17
|
const cb = useRef<Noop | void>()
|
|
18
18
|
|
|
19
19
|
useEffect(() => {
|
|
@@ -37,21 +37,15 @@ export default function useWindowEffect(fn: () => Noop | void, deps: Array<any>)
|
|
|
37
37
|
const deactivate = pre?.path === browserWindow.path
|
|
38
38
|
if (activate) {
|
|
39
39
|
cb.current = fn()
|
|
40
|
-
console.log('activate', browserWindow.path)
|
|
40
|
+
// console.log('activate', browserWindow.path)
|
|
41
41
|
}
|
|
42
42
|
if (deactivate) {
|
|
43
43
|
cb.current && cb.current()
|
|
44
|
-
console.log('deactivate', browserWindow.path)
|
|
44
|
+
// console.log('deactivate', browserWindow.path)
|
|
45
45
|
}
|
|
46
46
|
}
|
|
47
|
-
// { fireImmediately: true }
|
|
48
47
|
)
|
|
49
48
|
cb.current = fn()
|
|
50
|
-
|
|
51
|
-
return () => {
|
|
52
|
-
console.log('dispose', browserWindow.path)
|
|
53
|
-
dispose()
|
|
54
|
-
cb.current && cb.current()
|
|
55
|
-
}
|
|
49
|
+
return dispose
|
|
56
50
|
}, deps)
|
|
57
51
|
}
|
|
@@ -14,7 +14,7 @@ export interface VBrowserWindow {
|
|
|
14
14
|
export interface VBrowserProps {
|
|
15
15
|
/** 窗口数量限制 */
|
|
16
16
|
maxLength?: number
|
|
17
|
-
/** 准备就绪 */
|
|
17
|
+
/** 准备就绪 (读取Storage) */
|
|
18
18
|
onReady?: Function
|
|
19
19
|
/** 重新打开vBrowser时恢复已打开窗口, 默认为true */
|
|
20
20
|
restore?: boolean
|
|
@@ -28,7 +28,13 @@ export interface VBrowserProps {
|
|
|
28
28
|
auth?: (from?: VBrowserWindow, to?: VBrowserWindow) => Promise<boolean> | boolean
|
|
29
29
|
/**
|
|
30
30
|
* 错误码参考
|
|
31
|
+
*
|
|
31
32
|
* code: 0, message: '超过最大允许的窗口数量'
|
|
33
|
+
*
|
|
34
|
+
* code: 1, message: '鉴权失败'
|
|
35
|
+
*
|
|
36
|
+
* code: 2, message: '路由不存在‘
|
|
37
|
+
*
|
|
32
38
|
*/
|
|
33
39
|
onError?: (error: { code: number; message: string }) => void
|
|
34
40
|
/** 打开窗口如果没有传入标题,则使用此方法取标题 */
|
|
@@ -64,7 +64,7 @@ const VBrowserContainer: FC<{ className?: string }> = observer(
|
|
|
64
64
|
createPortal(
|
|
65
65
|
pages.map((page, i) => {
|
|
66
66
|
return (
|
|
67
|
-
<BrowserWindowContext.Provider key={i} value={page}>
|
|
67
|
+
<BrowserWindowContext.Provider key={i} value={page.path}>
|
|
68
68
|
<WindowWrapper key={i} path={page.path} />
|
|
69
69
|
</BrowserWindowContext.Provider>
|
|
70
70
|
)
|
|
@@ -1,9 +1,11 @@
|
|
|
1
1
|
/* eslint-disable dot-notation */
|
|
2
2
|
import { get } from 'lodash'
|
|
3
3
|
import { observer } from 'mobx-react'
|
|
4
|
-
import React, { createRef, FC, useContext, useEffect } from 'react'
|
|
4
|
+
import React, { createRef, FC, lazy, Suspense, useContext, useEffect } from 'react'
|
|
5
|
+
import { Loading } from '../../loading'
|
|
5
6
|
import { NProgress } from '../../n_progress'
|
|
6
7
|
import BrowserContext from '../context/browser'
|
|
8
|
+
import BrowserWindowContext from '../context/browserWindow'
|
|
7
9
|
import { CacheItem } from '../types'
|
|
8
10
|
import { pages } from '../v_browser'
|
|
9
11
|
|
|
@@ -34,27 +36,25 @@ const WindowWrapper: FC<WindowWrapperProps> = ({ path }) => {
|
|
|
34
36
|
const page = pages.find((p) => p.path === path)
|
|
35
37
|
if (!page) throw new Error('[VBrowser] page not found: ' + path)
|
|
36
38
|
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
NProgress.done()
|
|
57
|
-
})
|
|
39
|
+
const loading = (
|
|
40
|
+
<div className='tw-w-full tw-h-full tw-flex tw-items-center tw-justify-center'>
|
|
41
|
+
<Loading size='24' />
|
|
42
|
+
</div>
|
|
43
|
+
)
|
|
44
|
+
const Component = lazy(page.loader)
|
|
45
|
+
const vNode = (
|
|
46
|
+
<div
|
|
47
|
+
className='v-browser-window-content'
|
|
48
|
+
data-vbrowser-window={path}
|
|
49
|
+
ref={createRef()}
|
|
50
|
+
>
|
|
51
|
+
<Suspense fallback={loading}>
|
|
52
|
+
<Component />
|
|
53
|
+
</Suspense>
|
|
54
|
+
</div>
|
|
55
|
+
) as CacheItem['vNode']
|
|
56
|
+
browser['_setCache'](path, { vNode })
|
|
57
|
+
browser['_fire']('show', w!)
|
|
58
58
|
return
|
|
59
59
|
}
|
|
60
60
|
|
|
@@ -15,7 +15,7 @@ export const pages = req.keys().map((key) => {
|
|
|
15
15
|
}
|
|
16
16
|
})
|
|
17
17
|
|
|
18
|
-
const
|
|
18
|
+
export const VBROWSER_STORAGE_KEY = 'gm_vbrowser-cache'
|
|
19
19
|
|
|
20
20
|
type EventName = 'error' | 'change' | 'close' | 'show'
|
|
21
21
|
|
|
@@ -36,7 +36,7 @@ class VBrowser implements VBrowser {
|
|
|
36
36
|
</BrowserContext.Provider>
|
|
37
37
|
)
|
|
38
38
|
// this.open = debounce(this.open).bind(this) as typeof this.open
|
|
39
|
-
this.
|
|
39
|
+
this._restoreSession().then(async () => {
|
|
40
40
|
await when(() => this.mounted)
|
|
41
41
|
this.props.onReady && this.props.onReady()
|
|
42
42
|
return null
|
|
@@ -65,7 +65,7 @@ class VBrowser implements VBrowser {
|
|
|
65
65
|
if (ignored) {
|
|
66
66
|
const i = this.windows.indexOf(oldWindow!)
|
|
67
67
|
this.windows.splice(i, 1)
|
|
68
|
-
delete this._cache[
|
|
68
|
+
delete this._cache[oldWindow?.path!]
|
|
69
69
|
}
|
|
70
70
|
|
|
71
71
|
if (typeof w === 'number') {
|
|
@@ -81,7 +81,7 @@ class VBrowser implements VBrowser {
|
|
|
81
81
|
|
|
82
82
|
this.props.onChange &&
|
|
83
83
|
this.props.onChange(oldWindow, this.windows[this.activeIndex], this.windows)
|
|
84
|
-
this.
|
|
84
|
+
this._stashSession()
|
|
85
85
|
}
|
|
86
86
|
|
|
87
87
|
/** 打开新子窗口, 子窗口已存在则判断query是否相等,相等则切换,不相等则隐性销毁重新加载;子窗口不存在则新建子窗口;
|
|
@@ -110,9 +110,16 @@ class VBrowser implements VBrowser {
|
|
|
110
110
|
} else {
|
|
111
111
|
pass = (auth(this.activeWindow, w as VBrowserWindow) as boolean) ?? false
|
|
112
112
|
}
|
|
113
|
-
if (!pass)
|
|
113
|
+
if (!pass) {
|
|
114
|
+
this._fire('error', { code: 1, message: '鉴权失败' })
|
|
115
|
+
return
|
|
116
|
+
}
|
|
114
117
|
if (!pages.find((p) => p.path === (w as VBrowserWindow).path)) {
|
|
115
|
-
|
|
118
|
+
this._fire('error', {
|
|
119
|
+
code: 2,
|
|
120
|
+
message: `无法找到页面 ${w.path}, 可用路径:${pages.map((p) => p.path)}`,
|
|
121
|
+
})
|
|
122
|
+
return
|
|
116
123
|
}
|
|
117
124
|
// #endregion
|
|
118
125
|
|
|
@@ -123,8 +130,7 @@ class VBrowser implements VBrowser {
|
|
|
123
130
|
)
|
|
124
131
|
if (index === -1) {
|
|
125
132
|
if (this.props.maxLength && this.windows.length >= this.props.maxLength) {
|
|
126
|
-
this.
|
|
127
|
-
this.props.onError({ code: 0, message: '超过最大允许的窗口数量' })
|
|
133
|
+
this._fire('error', { code: 0, message: '超过最大允许的窗口数量' })
|
|
128
134
|
return
|
|
129
135
|
}
|
|
130
136
|
|
|
@@ -151,16 +157,18 @@ class VBrowser implements VBrowser {
|
|
|
151
157
|
// #region 打开新浏览器窗口
|
|
152
158
|
if (target === '_blank') {
|
|
153
159
|
// 避免继承
|
|
154
|
-
const currentCache = JSON.parse(
|
|
160
|
+
const currentCache = JSON.parse(
|
|
161
|
+
sessionStorage.getItem(VBROWSER_STORAGE_KEY) || '{}'
|
|
162
|
+
)
|
|
155
163
|
const newCache = { windows: [] as VBrowserWindow[], activeIndex: 0 }
|
|
156
164
|
newCache.windows.push(...this.windows.filter((w) => !w.closeable))
|
|
157
165
|
newCache.windows.push(w)
|
|
158
166
|
newCache.activeIndex = newCache.windows.findIndex(
|
|
159
167
|
(item) => item.path === (w as VBrowserWindow).path
|
|
160
168
|
)
|
|
161
|
-
sessionStorage.setItem(
|
|
169
|
+
sessionStorage.setItem(VBROWSER_STORAGE_KEY, JSON.stringify(newCache))
|
|
162
170
|
window.open(`#${w.path}?${stringify(w.query || {})}`, '_blank')
|
|
163
|
-
sessionStorage.setItem(
|
|
171
|
+
sessionStorage.setItem(VBROWSER_STORAGE_KEY, JSON.stringify(currentCache))
|
|
164
172
|
}
|
|
165
173
|
// #endregion
|
|
166
174
|
}
|
|
@@ -213,26 +221,31 @@ class VBrowser implements VBrowser {
|
|
|
213
221
|
}
|
|
214
222
|
|
|
215
223
|
// 保存已开窗口
|
|
216
|
-
private async
|
|
224
|
+
private async _stashSession() {
|
|
217
225
|
const windows = this.windows.slice().map((item) => ({ ...item }))
|
|
218
226
|
const string = JSON.stringify({
|
|
219
227
|
windows,
|
|
220
228
|
activeIndex: this.activeIndex,
|
|
221
229
|
})
|
|
222
|
-
sessionStorage.setItem(
|
|
230
|
+
sessionStorage.setItem(VBROWSER_STORAGE_KEY, string)
|
|
223
231
|
}
|
|
224
232
|
|
|
225
233
|
// 恢复已开窗口
|
|
226
|
-
private async
|
|
234
|
+
private async _restoreSession() {
|
|
227
235
|
await new Promise((resolve) => setTimeout(resolve, 100))
|
|
228
236
|
const { windows = [], activeIndex = 0 } = JSON.parse(
|
|
229
|
-
sessionStorage.getItem(
|
|
237
|
+
sessionStorage.getItem(VBROWSER_STORAGE_KEY) || '{}'
|
|
230
238
|
)
|
|
231
239
|
if (windows.length === 0) return
|
|
232
240
|
this.windows = windows
|
|
233
241
|
this.open(windows[activeIndex])
|
|
234
242
|
}
|
|
235
243
|
|
|
244
|
+
/** 清除会话缓存,使重新进入不恢复vbrowser窗口标签栏 */
|
|
245
|
+
clearSession() {
|
|
246
|
+
sessionStorage.removeItem(VBROWSER_STORAGE_KEY)
|
|
247
|
+
}
|
|
248
|
+
|
|
236
249
|
/** 隐藏标签栏 */
|
|
237
250
|
hideTabs() {
|
|
238
251
|
this._hidingTabs = true
|
|
@@ -264,6 +277,9 @@ class VBrowser implements VBrowser {
|
|
|
264
277
|
private _fire(eventName: EventName, ...args: any[]) {
|
|
265
278
|
const events = this._events[eventName] || []
|
|
266
279
|
events.forEach((item) => item.event(...args))
|
|
280
|
+
if (eventName === 'error') {
|
|
281
|
+
this.props.onError && this.props.onError(args?.[0])
|
|
282
|
+
}
|
|
267
283
|
}
|
|
268
284
|
}
|
|
269
285
|
|