Skip to content

Commit 500bf23

Browse files
committed
feat: 用户信息和系统设置增加跨页面通信能力
1 parent dcb8eaa commit 500bf23

8 files changed

Lines changed: 95 additions & 46 deletions

File tree

src/TabCommunicationOnMessage.ts

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
import store from './store/index'
2+
import i18n from './locales/index'
3+
import TabCommunication from '@/utils/TabCommunication'
4+
import { onlyChangeTheme } from './store/themeSlice'
5+
import { onlyChangeSystemSet } from './store/systemSetSlice'
6+
import { type ThemeType, themeList, type LocaleType, localeList } from './config'
7+
import { changeHtmlLang } from '@/utils/changeHtmlLang'
8+
import { onlyLoginFn, onlyLogoutFn } from './store/index'
9+
10+
TabCommunication.onMessage((data) => {
11+
if (data.type === 'theme_channel') {
12+
if (themeList.includes(data.data)) {
13+
store.dispatch(onlyChangeTheme(data.data as ThemeType))
14+
}
15+
} else if (data.type === 'locales_channel') {
16+
if (localeList.includes(data.data)) {
17+
i18n.changeLanguage(data.data as LocaleType)
18+
changeHtmlLang(data.data as LocaleType)
19+
}
20+
} else if (data.type === 'system_set_channel') {
21+
store.dispatch(onlyChangeSystemSet(data.data))
22+
} else if (data.type === 'user_channel') {
23+
if (data.data.id) {
24+
onlyLoginFn(data.data)
25+
} else {
26+
onlyLogoutFn()
27+
}
28+
}
29+
})
30+
window.addEventListener('unload', () => {
31+
TabCommunication.close()
32+
})

src/layout/LayoutUser.tsx

Lines changed: 2 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -3,13 +3,13 @@ import cn from 'classnames'
33
import { LogoutOutlined, UserOutlined } from '@ant-design/icons'
44
import { useUser } from '@/storeHooks/useUser'
55
import { useNavigate } from 'react-router'
6-
import config from '@/config'
76
import { useTheme } from '@/storeHooks/useTheme'
87
import { useTranslation } from 'react-i18next'
98
import { useAClassStyles, usePopoverItemStyles } from '@/Hooks/useStyles'
9+
import { logoutFn } from '@/store/index'
1010

1111
function LayoutUser({ className }: { className?: string }) {
12-
const { name, img, badge, changeUserInfo } = useUser()
12+
const { name, img, badge } = useUser()
1313
const { theme } = useTheme()
1414
const navigate = useNavigate()
1515
const { t } = useTranslation()
@@ -24,12 +24,6 @@ function LayoutUser({ className }: { className?: string }) {
2424
}
2525
}
2626

27-
const logoutFn = () => {
28-
localStorage.removeItem(config.loginLocalStorageKey)
29-
changeUserInfo({ id: '', name: '', img: undefined, badge: 0, permissionList: [] })
30-
navigate('/login')
31-
}
32-
3327
return (
3428
<Popover content={
3529
[

src/main.tsx

Lines changed: 2 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1,36 +1,16 @@
11
import { StrictMode } from 'react'
22
import { createRoot } from 'react-dom/client'
33
import './index.css'
4-
import i18n from './locales/index'
4+
import './locales/index'
55
import { RouterProvider } from 'react-router/dom'
66
import router from './router'
77
import store from './store/index'
88
import { Provider } from 'react-redux'
99
import { setupProdMockServer } from './mockProdServer'
10-
import TabCommunication from '@/utils/TabCommunication'
11-
import { onlyChangeTheme } from './store/themeSlice'
12-
import { type ThemeType, themeList, type LocaleType, localeList } from './config'
13-
import { changeHtmlLang } from '@/utils/changeHtmlLang'
10+
import './TabCommunicationOnMessage'
1411

1512
if (import.meta.env.PROD) setupProdMockServer()
1613

17-
TabCommunication.onMessage((data) => {
18-
console.log('TabCommunication', data)
19-
if (data.type === 'theme_channel') {
20-
if (themeList.includes(data.data)) {
21-
store.dispatch(onlyChangeTheme(data.data as ThemeType))
22-
}
23-
} else if (data.type === 'locales_channel') {
24-
if (localeList.includes(data.data)) {
25-
i18n.changeLanguage(data.data as LocaleType)
26-
changeHtmlLang(data.data as LocaleType)
27-
}
28-
}
29-
})
30-
window.addEventListener('unload', () => {
31-
TabCommunication.close()
32-
})
33-
3414
createRoot(document.getElementById('root')!).render(
3515
<StrictMode>
3616
<Provider store={store}>

src/pages/Login.tsx

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -5,10 +5,10 @@ import { useNavigate } from 'react-router'
55
import LayoutTheme from '@/layout/LayoutTheme'
66
import LayoutLocale from '@/layout/LayoutLocale'
77
import config from '@/config'
8-
import { useUser } from '@/storeHooks/useUser'
98
import { useTranslation } from 'react-i18next'
109
import FormPassword from '@/components/FormPassword'
1110
import FormCaptcha from '@/components/FormCaptcha'
11+
import { loginFn } from '@/store/index'
1212

1313
type LoginType = 'phone' | 'account'
1414
interface LoginFormValues {
@@ -33,7 +33,6 @@ function Login() {
3333
const { message } = App.useApp()
3434
const { token } = antdTheme.useToken()
3535
const [ loginType, setLoginType ] = useState<LoginType>('account')
36-
const { changeUserInfo } = useUser()
3736
const [ form ] = Form.useForm()
3837
const rememberLogin = localStorage.getItem('rememberLogin')
3938
const formValues: LoginFormValues = {
@@ -80,11 +79,9 @@ function Login() {
8079
badge: 10,
8180
permissionList: values.username === 'admin' ? ['01', '02', '03', '09'] : ['01', '02'],
8281
}
83-
changeUserInfo(userInfo)
84-
localStorage.setItem(config.loginLocalStorageKey, JSON.stringify(userInfo))
8582
await waitTime(2000)
8683
message.success(t('login.Login success', { defaultValue: '登录成功' }))
87-
navigate('/')
84+
loginFn(userInfo)
8885
}}
8986
size='large'
9087
style={{

src/store/index.ts

Lines changed: 31 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,12 @@
11
import { configureStore } from '@reduxjs/toolkit'
2+
import config from '@/config'
3+
import router from '@/router'
24
import themeReducer from './themeSlice'
35
import routeLoadingReducer from './routeLoadingSlice'
46
import layoutStateReducer from './layoutStateSlice'
57
import activitysReducer from './activitysSlice'
68
import layoutTabsReducer from './layoutTabsSlice'
7-
import userReducer from './userSlice'
9+
import userReducer, { changeUserInfo, onlyChangeUserInfo, type UserState } from './userSlice'
810
import watermarkReducer from './watermarkSlice'
911
import systemSetReducer from './systemSetSlice'
1012

@@ -25,3 +27,31 @@ export default store
2527

2628
export type RootState = ReturnType<typeof store.getState>
2729
export type AppDispatch = typeof store.dispatch
30+
31+
const BASE_URL = import.meta.env.BASE_URL
32+
export const loginFn = (userInfo: UserState['value']) => {
33+
localStorage.setItem(config.loginLocalStorageKey, JSON.stringify(userInfo))
34+
store.dispatch(changeUserInfo(userInfo))
35+
router.navigate('/')
36+
}
37+
export const onlyLoginFn = (userInfo: UserState['value']) => {
38+
store.dispatch(onlyChangeUserInfo(userInfo))
39+
const pathname = window.location.pathname
40+
if (pathname === BASE_URL + 'login') {
41+
router.navigate('/')
42+
}
43+
}
44+
export const logoutFn = () => {
45+
localStorage.removeItem(config.loginLocalStorageKey)
46+
store.dispatch(changeUserInfo({ id: '', name: '', img: undefined, badge: 0, permissionList: [] }))
47+
router.navigate('/login')
48+
}
49+
export const onlyLogoutFn = () => {
50+
store.dispatch(onlyChangeUserInfo({ id: '', name: '', img: undefined, badge: 0, permissionList: [] }))
51+
const pathname = window.location.pathname
52+
const whiteList = config.whiteList.map(x => BASE_URL + x.replace(/^\//, ''))
53+
if (!whiteList.includes(pathname)) {
54+
router.navigate('/login')
55+
}
56+
}
57+

src/store/systemSetSlice.ts

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import { createSlice, type PayloadAction } from '@reduxjs/toolkit'
22
import config from '@/config'
3+
import TabCommunication from '@/utils/TabCommunication'
34

45
export interface SystemSetState {
56
colorPrimary: string | undefined
@@ -21,10 +22,17 @@ export const systemSetSlice = createSlice({
2122
changeSystemSet: (state, action: PayloadAction<SystemSetState>) => {
2223
state.value = action.payload
2324
localStorage.setItem(config.systemSet?.localStorageKey || 'react-components-system-set', JSON.stringify(state.value))
25+
TabCommunication.postMessage({
26+
type: 'system_set_channel',
27+
data: state.value
28+
})
29+
},
30+
onlyChangeSystemSet: (state, action: PayloadAction<SystemSetState>) => {
31+
state.value = action.payload
2432
}
2533
}
2634
})
2735

28-
export const { changeSystemSet } = systemSetSlice.actions
36+
export const { changeSystemSet, onlyChangeSystemSet } = systemSetSlice.actions
2937

3038
export default systemSetSlice.reducer

src/store/userSlice.ts

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import { createSlice, type PayloadAction } from '@reduxjs/toolkit'
22
import config from '@/config'
3+
import TabCommunication from '@/utils/TabCommunication'
34

45
export type UserState = {
56
value: {
@@ -33,6 +34,13 @@ export const userSlice = createSlice({
3334
changeUserInfo: (state, action: PayloadAction<UserState['value']>) => {
3435
state.value = action.payload
3536
localStorage.setItem(config.loginLocalStorageKey, JSON.stringify(state.value))
37+
TabCommunication.postMessage({
38+
type: 'user_channel',
39+
data: state.value
40+
})
41+
},
42+
onlyChangeUserInfo: (state, action: PayloadAction<UserState['value']>) => {
43+
state.value = action.payload
3644
},
3745
changeBadge: (state, action: PayloadAction<number>) => {
3846
state.value.badge = action.payload
@@ -45,6 +53,6 @@ export const userSlice = createSlice({
4553
}
4654
})
4755

48-
export const { changeUserInfo, changeBadge, changePermissionList } = userSlice.actions
56+
export const { changeUserInfo, onlyChangeUserInfo, changeBadge, changePermissionList } = userSlice.actions
4957

5058
export default userSlice.reducer

src/utils/TabCommunication.ts

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,13 @@
11
import pkg from '../../package.json'
22

3+
export type TabMessageType = 'theme_channel' | 'locales_channel' | 'system_set_channel' | 'user_channel'
4+
export type TabMessageData = {
5+
type: TabMessageType
6+
data: any
7+
}
8+
39
export interface TabMessageCallback {
4-
(data: {
5-
type: 'theme_channel' | 'locales_channel'
6-
data: any
7-
}): void;
10+
(data: TabMessageData): void;
811
}
912

1013
export class TabCommunication {
@@ -85,10 +88,7 @@ export class TabCommunication {
8588
* 发送消息
8689
* @param data - 要发送的消息(支持任意可序列化类型:对象、数组、字符串等)
8790
*/
88-
postMessage(data: {
89-
type: string
90-
data: any
91-
}): void {
91+
postMessage(data: TabMessageData): void {
9292
if (this.isSupported && this.bc) {
9393
// 方案1:BroadcastChannel 直接发送
9494
this.bc.postMessage({

0 commit comments

Comments
 (0)