浏览代码

2023.2.2 优化返回主菜单保存数据

xyh 2 年之前
父节点
当前提交
cacc35c9a6

+ 2 - 0
packages/app/package.json

@@ -18,6 +18,7 @@
     "classnames": "^2.3.2",
     "fast-deep-equal": "^3.1.3",
     "immer": "^9.0.19",
+    "lodash-es": "^4.17.21",
     "lottie-react": "^2.3.1",
     "react": "^18.2.0",
     "react-dom": "^18.2.0",
@@ -34,6 +35,7 @@
     "@tanstack/react-query-devtools": "^4.23.0",
     "@testing-library/jest-dom": "^5.16.5",
     "@testing-library/react": "^13.4.0",
+    "@types/lodash-es": "^4.17.6",
     "@types/react": "^18.0.27",
     "@types/react-dom": "^18.0.10",
     "@types/react-modal": "^3.13.1"

+ 2 - 2
packages/app/src/apis/request.ts

@@ -1,6 +1,6 @@
 import {BaseResultContent} from '@models';
 import {userStore} from '@stores';
-import {NETWORK_URL} from '@utils';
+import {NETWORK_ERROR_TIPS, NETWORK_URL} from '@utils';
 import {message} from 'antd';
 import axios from 'axios';
 
@@ -46,7 +46,7 @@ export async function request<T, R extends BaseResultContent<any>>(options: {
 
     if (res.msg !== '200' && !skipError) message.error(res.errMsg);
   } catch (error) {
-    res = {msg: '510', errMsg: '请求失败,请稍后再试'};
+    res = {msg: '510', errMsg: NETWORK_ERROR_TIPS};
 
     if (!skipError) message.error(res.errMsg);
   }

+ 1 - 1
packages/app/src/hooks/useContextSection.ts

@@ -3,7 +3,7 @@ import {useLatest} from 'ahooks';
 import {useMemo} from 'react';
 import {useContextSelector, Context} from 'use-context-selector';
 
-const selectorFn = <T, R>(state: T) => state ;
+const selectorFn = <T>(state: T) => state ;
 
 export function useContextSection<T, R>(
   context: Context<T>,

+ 11 - 7
packages/app/src/hooks/usePageContext.ts

@@ -8,26 +8,30 @@ export type PageContextState = {
 };
 
 export type PageContextAction = {
-  type: 'editPage',
+  type: 'EDIT_PAGE',
   payload: PageContextState,
+} | {
+  type: 'RESET'
 };
 
+export function pageContextInit(options?: {page: number; pageSize: number}): PageContextState {
+  const {page, pageSize} = options ?? {};
+  return {page: page ?? 1, pageSize: pageSize ?? Number(PAGE_SIZE_LIST[0])};
+}
+
 function pageReduce(state: PageContextState, action: PageContextAction): PageContextState {
   const {type} = action;
 
   switch (type) {
-    case 'editPage':
+    case 'EDIT_PAGE':
       return action.payload;
+    case 'RESET':
+      return pageContextInit();
     default:
       return state;
   }
 }
 
-export function pageContextInit(options?: {page: number; pageSize: number}): PageContextState {
-  const {page, pageSize} = options ?? {};
-  return {page: page ?? 1, pageSize: pageSize ?? Number(PAGE_SIZE_LIST[0])};
-}
-
 export function usePageContextReducer(options?: {page: number; pageSize: number}) {
   return useReducer(pageReduce, pageContextInit(options));
 }

+ 9 - 4
packages/app/src/pages/department/filter/hooks.ts

@@ -2,6 +2,8 @@ import {useState} from 'react';
 import {context, pageContext} from '../context';
 import {exportDepartment} from '@apis';
 import {useContextSection} from '@hooks';
+import {EXPORT_ERROR_TIPS, exportFile} from '@utils';
+import {message} from 'antd';
 
 export function useField() {
   const [state, setState] = useState({name: '', code: ''});
@@ -29,10 +31,13 @@ export function useHandle(name: string, code: string) {
       limit: pageSize.toString(),
       code,
       departmentName: name,
-    }).then(function(res: Blob) {
-      const _url = URL.createObjectURL(res);
-      open(_url, '_blank');
-    });
+    })
+      .then(function(res: Blob) {
+        exportFile(res);
+      })
+      .catch(function() {
+        message.error(EXPORT_ERROR_TIPS);
+      });
   }
 
   return {onSearch, onExport};

+ 1 - 1
packages/app/src/pages/department/table/hooks.tsx

@@ -35,7 +35,7 @@ export function useList() {
   );
 
   function onPageChange(page: number, pageSize: number) {
-    dispatch({type: 'editPage', payload: {page, pageSize}});
+    dispatch({type: 'EDIT_PAGE', payload: {page, pageSize}});
   }
 
   return [{count, data, isFetching, page, pageSize}, {onPageChange, refetch}] as const;

+ 16 - 0
packages/app/src/pages/menu/child-menu/index.tsx

@@ -0,0 +1,16 @@
+import {Layout} from 'antd';
+import {FC} from 'react';
+import ReactModal from 'react-modal';
+import Menu from '..';
+
+const ChildMenuModal: FC = function() {
+  return (
+    <ReactModal isOpen ariaHideApp={false}>
+      <Layout.Content>
+        <Menu />
+      </Layout.Content>
+    </ReactModal>
+  );
+};
+
+export default ChildMenuModal;

+ 4 - 1
packages/app/src/pages/menu/context.ts

@@ -8,7 +8,7 @@ type State = {
   name: string;
 };
 
-type Action = {type: 'SEARCH', payload: State};
+type Action = {type: 'SEARCH', payload: State} | {type: 'RESET'};
 
 function reducer(state: State, action: Action): State {
   const {type} = action;
@@ -17,6 +17,8 @@ function reducer(state: State, action: Action): State {
     case 'SEARCH': {
       return action.payload;
     }
+    case 'RESET':
+      return {name: ''};
     default:
       return state;
   }
@@ -36,3 +38,4 @@ export const context = createContext<[State, Dispatch<Action>]>([initState(), ()
 
 /** 页码管理 */
 export const pageContext = createPageContext();
+

+ 7 - 2
packages/app/src/pages/menu/filter/hooks.ts

@@ -1,9 +1,14 @@
-import {useState} from 'react';
+import {useEffect, useState} from 'react';
 import {context} from '../context';
 import {useContextSection} from '@hooks';
 
 export function useField() {
-  const [state, setState] = useState('');
+  const name = useContextSection(context, state => state[0].name);
+  const [state, setState] = useState(name);
+
+  useEffect(function() {
+    setState(name);
+  }, [name]);
 
   function onChange(val: string) {
     setState(val);

+ 41 - 12
packages/app/src/pages/menu/index.tsx

@@ -3,42 +3,71 @@ import {FC, ReactNode, useEffect} from 'react';
 import {context, pageContext, useContextReducer} from './context';
 import {usePageContextReducer} from '@hooks';
 import TableList from './table';
-import {useLocation, useNavigate} from 'react-router-dom';
+import {useLocation} from 'react-router-dom';
 import {MENU_PATH} from '@routes';
+import {clearHistoryState} from '@utils';
 
 const MenuProvider: FC<{children: ReactNode}> = function({children}) {
   const state = useContextReducer();
+  const dispatch = state[1];
   const {Provider} = context;
 
+  const {state: locationState, pathname} = useLocation();
+
+  /**
+   * 为主菜单时如果有state数据更新为state数据
+   * 为二级菜单时重置数据
+   */
+  useEffect(function() {
+    if (pathname === MENU_PATH)
+      locationState && dispatch({type: 'SEARCH', payload: {name: locationState.name}});
+    else
+      dispatch({type: 'RESET'});
+  }, [dispatch, locationState, pathname]);
+
   return <Provider value={state}>{children}</Provider>;
 };
 
 const PageProvider: FC<{children: ReactNode}> = function({children}) {
-  const {state: locationState} = useLocation();
-  const state = usePageContextReducer(locationState);
+  const {state: locationState, pathname} = useLocation();
+  const useLocationState = pathname === MENU_PATH;
 
+  const state = usePageContextReducer(useLocationState && locationState);
+  const dispatch = state[1];
   const {Provider} = pageContext;
 
-  // 为了清除state 防止刷新后依旧使用state
-  const navigate = useNavigate();
+  // 为了清除state 防止刷新后依旧使用state导致页码等数据错误
+  useEffect(function() {
+    useLocationState && locationState && clearHistoryState();
+  }, [locationState, useLocationState]);
+
+  /**
+   * 为主菜单时如果有state数据更新为state数据
+   * 为二级菜单时重置数据
+   */
   useEffect(function() {
-    if (locationState?.pathValue === MENU_PATH)
-      navigate(MENU_PATH);
-  }, [navigate, locationState?.pathValue]);
+    if (useLocationState)
+      locationState && dispatch({
+        type: 'EDIT_PAGE',
+        payload: {page: locationState.page, pageSize: locationState.pageSize},
+      });
+    else
+      dispatch({type: 'RESET'});
+  }, [dispatch, locationState, useLocationState]);
 
   return <Provider value={state}>{children}</Provider>;
 };
 
 const Menu: FC = function() {
   return (
-    <MenuProvider>
-      <PageProvider>
+    <PageProvider>
+      <MenuProvider>
         <main className='content-main'>
           <Filter />
           <TableList />
         </main>
-      </PageProvider>
-    </MenuProvider>
+      </MenuProvider>
+    </PageProvider>
   );
 };
 

+ 1 - 1
packages/app/src/pages/menu/table/hooks.tsx

@@ -40,7 +40,7 @@ export function useList() {
   );
 
   function onPageChange(page: number, pageSize: number) {
-    dispatch({type: 'editPage', payload: {page, pageSize}});
+    dispatch({type: 'EDIT_PAGE', payload: {page, pageSize}});
   }
 
   return [{count, isFetching, data, page, pageSize}, {refetch, onPageChange}] as const;

+ 3 - 0
packages/app/src/utils/clearHistoryState.ts

@@ -0,0 +1,3 @@
+export function clearHistoryState() {
+  history.replaceState(null, document.title);
+}

+ 3 - 1
packages/app/src/utils/constants.ts

@@ -1,3 +1,5 @@
 export const USER_TOKEN_STORAGE = 'user_token';
-export const PAGE_SIZE_LIST = ['10', '30', '50', '80', '100'];
+export const PAGE_SIZE_LIST = ['1', '10', '30', '50', '80', '100'];
 export const NETWORK_URL = 'http://192.168.0.113:9560';
+export const EXPORT_ERROR_TIPS = '导出错误,请稍后再试';
+export const NETWORK_ERROR_TIPS = '请求失败,请稍后再试';

+ 4 - 0
packages/app/src/utils/exportFile.ts

@@ -0,0 +1,4 @@
+export function exportFile(blob: Blob) {
+  const url = URL.createObjectURL(blob);
+  window.open(url, '_blank');
+}

+ 2 - 0
packages/app/src/utils/index.ts

@@ -1,2 +1,4 @@
 export * from './equal';
 export * from './constants';
+export * from './exportFile';
+export * from './clearHistoryState';

+ 10 - 1
pnpm-lock.yaml

@@ -47,6 +47,7 @@ importers:
       '@tanstack/react-query-devtools': ^4.23.0
       '@testing-library/jest-dom': ^5.16.5
       '@testing-library/react': ^13.4.0
+      '@types/lodash-es': ^4.17.6
       '@types/react': ^18.0.27
       '@types/react-dom': ^18.0.10
       '@types/react-modal': ^3.13.1
@@ -56,6 +57,7 @@ importers:
       classnames: ^2.3.2
       fast-deep-equal: ^3.1.3
       immer: ^9.0.19
+      lodash-es: ^4.17.21
       lottie-react: ^2.3.1
       react: ^18.2.0
       react-dom: ^18.2.0
@@ -76,6 +78,7 @@ importers:
       classnames: 2.3.2
       fast-deep-equal: 3.1.3
       immer: 9.0.19
+      lodash-es: 4.17.21
       lottie-react: 2.3.1_biqbaboplfbrettd7655fr4n2y
       react: 18.2.0
       react-dom: 18.2.0_react@18.2.0
@@ -91,6 +94,7 @@ importers:
       '@tanstack/react-query-devtools': 4.23.0_74ln4l2hialvxelty6zunzkpjm
       '@testing-library/jest-dom': 5.16.5
       '@testing-library/react': 13.4.0_biqbaboplfbrettd7655fr4n2y
+      '@types/lodash-es': 4.17.6
       '@types/react': 18.0.27
       '@types/react-dom': 18.0.10
       '@types/react-modal': 3.13.1
@@ -2788,9 +2792,14 @@ packages:
     resolution: {integrity: sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ==}
     dev: true
 
+  /@types/lodash-es/4.17.6:
+    resolution: {integrity: sha512-R+zTeVUKDdfoRxpAryaQNRKk3105Rrgx2CFRClIgRGaqDTdjsm8h6IYA8ir584W3ePzkZfst5xIgDwYrlh9HLg==}
+    dependencies:
+      '@types/lodash': 4.14.191
+    dev: true
+
   /@types/lodash/4.14.191:
     resolution: {integrity: sha512-BdZ5BCCvho3EIXw6wUCXHe7rS53AIDPLE+JzwgT+OsJk53oBfbSmZZ7CX4VaRoN78N+TJpFi9QPlfIVNmJYWxQ==}
-    dev: false
 
   /@types/mime/3.0.1:
     resolution: {integrity: sha512-Y4XFY5VJAuw0FgAqPNd6NNoV44jbq9Bz2L7Rh/J6jLTiHBSBJa9fxqQIvkIld4GsoDOcCbvzOUAbLPsSKKg+uA==}