refactor(store): 重构store模块,分离全局设置与用户信息,修改项目中的使用方法

master
钟良源 5 months ago
parent 8f2980f07f
commit 053449121b

@ -11,7 +11,6 @@ import {
IconLoading IconLoading
} from '@arco-design/web-react/icon'; } from '@arco-design/web-react/icon';
import { useSelector, useDispatch } from 'react-redux'; import { useSelector, useDispatch } from 'react-redux';
import { GlobalState } from '@/store';
import { GlobalContext } from '@/context'; import { GlobalContext } from '@/context';
import useLocale from '@/utils/useLocale'; import useLocale from '@/utils/useLocale';
import Settings from '../Settings'; import Settings from '../Settings';
@ -20,12 +19,12 @@ import useStorage from '@/utils/useStorage';
import { generatePermission } from '@/routes'; import { generatePermission } from '@/routes';
import logoImage from '@/public/assets/logo.png'; import logoImage from '@/public/assets/logo.png';
import useUser from '@/hooks/user'; import useUser from '@/hooks/user';
import { updateUserInfo } from '@/store'; import { updateUserInfo } from '@/store/user';
function Navbar({ show }: { show: boolean }) { function Navbar({ show }: { show: boolean }) {
const t = useLocale(); const t = useLocale();
const { logoutHooks } = useUser(); const { logoutHooks } = useUser();
const { userInfo, userLoading } = useSelector((state: GlobalState) => state); const { userInfo, userLoading } = useSelector((state) => state.user);
const dispatch = useDispatch(); const dispatch = useDispatch();
const [_, setUserStatus] = useStorage('userStatus'); const [_, setUserStatus] = useStorage('userStatus');

@ -1,5 +1,4 @@
import React, { useMemo } from 'react'; import React, { useMemo } from 'react';
import { GlobalState } from '@/store';
import { useSelector } from 'react-redux'; import { useSelector } from 'react-redux';
import authentication, { AuthParams } from '@/utils/authentication'; import authentication, { AuthParams } from '@/utils/authentication';
@ -11,7 +10,7 @@ const PermissionWrapper = (
props: React.PropsWithChildren<PermissionWrapperProps> props: React.PropsWithChildren<PermissionWrapperProps>
) => { ) => {
const { backup, requiredPermissions, oneOfPerm } = props; const { backup, requiredPermissions, oneOfPerm } = props;
const userInfo = useSelector((state: GlobalState) => state.userInfo); const userInfo = useSelector((state) => state.user);
const hasPermission = useMemo(() => { const hasPermission = useMemo(() => {
return authentication( return authentication(

@ -1,10 +1,9 @@
import React, { ReactNode } from 'react'; import React, { ReactNode } from 'react';
import { Switch, Divider, InputNumber } from '@arco-design/web-react'; import { Switch, Divider, InputNumber } from '@arco-design/web-react';
import { useSelector, useDispatch } from 'react-redux'; import { useSelector, useDispatch } from 'react-redux';
import { GlobalState } from '../../store';
import useLocale from '../../utils/useLocale'; import useLocale from '../../utils/useLocale';
import styles from './style/block.module.less'; import styles from './style/block.module.less';
import { updateSettings } from '@/store'; import { updateSettings } from '@/store/global';
export interface BlockProps { export interface BlockProps {
title?: ReactNode; title?: ReactNode;
@ -15,7 +14,7 @@ export interface BlockProps {
export default function Block(props: BlockProps) { export default function Block(props: BlockProps) {
const { title, options, children } = props; const { title, options, children } = props;
const locale = useLocale(); const locale = useLocale();
const settings = useSelector((state: GlobalState) => state.settings); const settings = useSelector((state) => state.global);
const dispatch = useDispatch(); const dispatch = useDispatch();
return ( return (

@ -3,15 +3,14 @@ import { Trigger, Typography } from '@arco-design/web-react';
import { SketchPicker } from 'react-color'; import { SketchPicker } from 'react-color';
import { generate, getRgbStr } from '@arco-design/color'; import { generate, getRgbStr } from '@arco-design/color';
import { useSelector, useDispatch } from 'react-redux'; import { useSelector, useDispatch } from 'react-redux';
import { GlobalState } from '../../store';
import useLocale from '@/utils/useLocale'; import useLocale from '@/utils/useLocale';
import styles from './style/color-panel.module.less'; import styles from './style/color-panel.module.less';
import { updateSettings } from '@/store'; import { updateSettings } from '@/store/global';
function ColorPanel() { function ColorPanel() {
const theme = const theme =
document.querySelector('body').getAttribute('arco-theme') || 'light'; document.querySelector('body').getAttribute('arco-theme') || 'light';
const settings = useSelector((state: GlobalState) => state.settings); const settings = useSelector((state) => state.global);
const locale = useLocale(); const locale = useLocale();
const themeColor = settings.themeColor; const themeColor = settings.themeColor;
const list = generate(themeColor, { list: true }); const list = generate(themeColor, { list: true });

@ -3,7 +3,6 @@ import { Drawer, Alert, Message } from '@arco-design/web-react';
import { IconSettings } from '@arco-design/web-react/icon'; import { IconSettings } from '@arco-design/web-react/icon';
import copy from 'copy-to-clipboard'; import copy from 'copy-to-clipboard';
import { useSelector } from 'react-redux'; import { useSelector } from 'react-redux';
import { GlobalState } from '../../store';
import Block from './block'; import Block from './block';
import ColorPanel from './color'; import ColorPanel from './color';
import IconButton from '../NavBar/IconButton'; import IconButton from '../NavBar/IconButton';
@ -17,7 +16,7 @@ function Setting(props: SettingProps) {
const { trigger } = props; const { trigger } = props;
const [visible, setVisible] = useState(false); const [visible, setVisible] = useState(false);
const locale = useLocale(); const locale = useLocale();
const settings = useSelector((state: GlobalState) => state.settings); const settings = useSelector((state) => state.global);
function onCopySettings() { function onCopySettings() {
copy(JSON.stringify(settings, null, 2)); copy(JSON.stringify(settings, null, 2));

@ -18,8 +18,8 @@ import Layout from './layout';
import '../mock'; import '../mock';
import { getUserInfo } from '@/api/user'; import { getUserInfo } from '@/api/user';
import { setSessionUserInfo } from '@/utils/auth'; import { setSessionUserInfo } from '@/utils/auth';
import store from '@/store'; // 只导入 store import store from '@/store';
import { updateUserInfo } from '@/store'; // 导入 action import { updateUserInfo } from '@/store/user';
interface RenderConfig { interface RenderConfig {

@ -21,7 +21,6 @@ import Navbar from '../components/NavBar';
import Footer from '../components/Footer'; import Footer from '../components/Footer';
import useRoute, { IRoute } from '@/routes'; import useRoute, { IRoute } from '@/routes';
import useLocale from '@/utils/useLocale'; import useLocale from '@/utils/useLocale';
import { GlobalState } from '@/store';
import getUrlParams from '@/utils/getUrlParams'; import getUrlParams from '@/utils/getUrlParams';
import styles from '@/style/layout.module.less'; import styles from '@/style/layout.module.less';
import NoAccess from '@/pages/exception/403'; import NoAccess from '@/pages/exception/403';
@ -62,9 +61,8 @@ function PageLayout({ children }: { children: ReactNode }) {
const pathname = router.pathname; const pathname = router.pathname;
const currentComponent = qs.parseUrl(pathname).url.slice(1); const currentComponent = qs.parseUrl(pathname).url.slice(1);
const locale = useLocale(); const locale = useLocale();
const { userInfo, settings, userLoading } = useSelector( const { settings } = useSelector((state) => state.global);
(state: GlobalState) => state const { userInfo, userLoading } = useSelector((state) => state.user);
);
const [collapsed, setCollapsed] = useState<boolean>(false); const [collapsed, setCollapsed] = useState<boolean>(false);

@ -3,7 +3,6 @@ import styles from './style/cardWrap.module.less';
import { getImageUrl } from '@/utils/pubUse'; import { getImageUrl } from '@/utils/pubUse';
import { Image, Popconfirm } from '@arco-design/web-react'; import { Image, Popconfirm } from '@arco-design/web-react';
import { IconEdit, IconDelete } from '@arco-design/web-react/icon'; import { IconEdit, IconDelete } from '@arco-design/web-react/icon';
import { GlobalState } from '@/store';
import { useSelector, useDispatch } from 'react-redux'; import { useSelector, useDispatch } from 'react-redux';
interface CardWrapProps { interface CardWrapProps {
@ -14,7 +13,7 @@ interface CardWrapProps {
} }
const CardWrap: React.FC<CardWrapProps> = ({ item, onEdit, onDelete, onClick }) => { const CardWrap: React.FC<CardWrapProps> = ({ item, onEdit, onDelete, onClick }) => {
const { userInfo, userLoading } = useSelector((state: GlobalState) => state); const { userInfo, userLoading } = useSelector((state) => state.user);
const handleEdit = (e: React.MouseEvent) => { const handleEdit = (e: React.MouseEvent) => {
e.stopPropagation(); e.stopPropagation();
if (onEdit) { if (onEdit) {
@ -58,7 +57,7 @@ const CardWrap: React.FC<CardWrapProps> = ({ item, onEdit, onDelete, onClick })
className={styles['avatar']} className={styles['avatar']}
width={25} width={25}
preview={false} preview={false}
src={userInfo.avatar} src={userInfo?.avatar}
/> />
<span>{item.createUser}</span> <span>{item.createUser}</span>
</div> </div>

@ -0,0 +1,25 @@
import { createSlice } from '@reduxjs/toolkit';
import defaultSettings from '../settings.json';
export interface GlobalState {
settings?: typeof defaultSettings;
}
const initialState: GlobalState = {
settings: defaultSettings
};
const globalSlice = createSlice({
name: 'global',
initialState,
reducers: {
updateSettings(state, action) {
state.settings = action.payload.settings;
}
}
});
export const { updateSettings } = globalSlice.actions;
export default globalSlice.reducer;

@ -1,47 +1,13 @@
import { createSlice, configureStore } from '@reduxjs/toolkit'; import { configureStore } from '@reduxjs/toolkit';
import defaultSettings from '../settings.json'; import globalReducer from './global';
import userReducer from './user';
export interface GlobalState {
settings?: typeof defaultSettings;
userInfo?: {
name?: string;
avatar?: string;
job?: string;
organization?: string;
location?: string;
email?: string;
permissions: Record<string, string[]>;
};
userLoading?: boolean;
}
const initialState: GlobalState = {
settings: defaultSettings,
userInfo: {
permissions: {}
}
};
const globalSlice = createSlice({
name: 'global',
initialState,
reducers: {
updateSettings(state, action) {
state.settings = action.payload.settings;
},
updateUserInfo(state, action) {
state.userInfo = action.payload.userInfo || initialState.userInfo;
state.userLoading = action.payload.userLoading;
}
}
});
// 保持与原来相同的 action creators 导出方式
export const { updateSettings, updateUserInfo } = globalSlice.actions;
// 创建 store // 创建 store
const store = configureStore({ const store = configureStore({
reducer: globalSlice.reducer reducer: {
global: globalReducer,
user: userReducer
}
}); });
export type RootState = ReturnType<typeof store.getState>; export type RootState = ReturnType<typeof store.getState>;

@ -0,0 +1,36 @@
import { createSlice } from '@reduxjs/toolkit';
export interface UserState {
userInfo?: {
name?: string;
avatar?: string;
job?: string;
organization?: string;
location?: string;
email?: string;
permissions: Record<string, string[]>;
};
userLoading?: boolean;
}
const initialState: UserState = {
userInfo: {
permissions: {}
},
userLoading: false
};
const userSlice = createSlice({
name: 'user',
initialState,
reducers: {
updateUserInfo(state, action) {
state.userInfo = action.payload.userInfo || initialState.userInfo;
state.userLoading = action.payload.userLoading;
}
}
});
export const { updateUserInfo } = userSlice.actions;
export default userSlice.reducer;
Loading…
Cancel
Save