恢复到没有加载效果的 除了效果别的还都是新的
This commit is contained in:
parent
02b1425689
commit
b07d192d20
@ -20,9 +20,9 @@ export default defineConfig({
|
|||||||
hash: true,
|
hash: true,
|
||||||
mock: false,
|
mock: false,
|
||||||
antd: {},
|
antd: {},
|
||||||
// dva: {
|
dva: {
|
||||||
// hmr: true
|
hmr: true
|
||||||
// },
|
},
|
||||||
history: {
|
history: {
|
||||||
type: REACT_APP_ENV === 'dev' ? "hash" : "memory",
|
type: REACT_APP_ENV === 'dev' ? "hash" : "memory",
|
||||||
// type: "hash"
|
// type: "hash"
|
||||||
@ -36,7 +36,7 @@ export default defineConfig({
|
|||||||
baseNavigator: true,
|
baseNavigator: true,
|
||||||
},
|
},
|
||||||
dynamicImport: {
|
dynamicImport: {
|
||||||
loading: '@/components/SmartLoading/index',
|
loading: '@/components/PageLoading/index',
|
||||||
},
|
},
|
||||||
targets: {
|
targets: {
|
||||||
ie: 11,
|
ie: 11,
|
||||||
|
|||||||
17
src/app.ts
17
src/app.ts
@ -7,7 +7,6 @@
|
|||||||
* @Description: 这是默认设置,请设置`customMade`, 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE
|
* @Description: 这是默认设置,请设置`customMade`, 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE
|
||||||
*/
|
*/
|
||||||
import globalState from './globalState';
|
import globalState from './globalState';
|
||||||
import { routePreloader } from './utils/routePreloader';
|
|
||||||
|
|
||||||
// import { getMicroAppRouteComponent } from 'umi';
|
// import { getMicroAppRouteComponent } from 'umi';
|
||||||
|
|
||||||
@ -30,22 +29,6 @@ export const qiankun = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// 应用启动时的初始化配置
|
|
||||||
export async function getInitialState() {
|
|
||||||
// 预加载关键路由以优化首屏加载
|
|
||||||
setTimeout(() => {
|
|
||||||
routePreloader.preloadCriticalRoutes().then(() => {
|
|
||||||
console.log('关键路由预加载完成');
|
|
||||||
}).catch(error => {
|
|
||||||
console.warn('关键路由预加载失败:', error);
|
|
||||||
});
|
|
||||||
}, 1000); // 延迟1秒后开始预加载,避免影响首屏渲染
|
|
||||||
|
|
||||||
return {
|
|
||||||
preloadEnabled: true,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
// export const patchRoutes = ({ routes }: any) => {
|
// export const patchRoutes = ({ routes }: any) => {
|
||||||
// console.info('routes', routes);
|
// console.info('routes', routes);
|
||||||
// routes[0].routes[1].routes[0].routes.forEach((item: any, index: number) => {
|
// routes[0].routes[1].routes[0].routes.forEach((item: any, index: number) => {
|
||||||
|
|||||||
@ -1,7 +0,0 @@
|
|||||||
.page-loading-container {
|
|
||||||
display: flex;
|
|
||||||
justify-content: center;
|
|
||||||
align-items: center;
|
|
||||||
height: 100vh;
|
|
||||||
width: 100%;
|
|
||||||
}
|
|
||||||
@ -1,13 +1,5 @@
|
|||||||
// import { PageLoading } from '@ant-design/pro-layout';
|
import { PageLoading } from '@ant-design/pro-layout';
|
||||||
|
|
||||||
// // loading components from code split
|
|
||||||
// // https://umijs.org/plugin/umi-plugin-react.html#dynamicimport
|
|
||||||
// export default PageLoading;
|
|
||||||
import React from 'react';
|
|
||||||
import SkeletonLoading from '../SkeletonLoading';
|
|
||||||
|
|
||||||
const PageLoading: React.FC = () => {
|
|
||||||
return <SkeletonLoading type="page" />;
|
|
||||||
};
|
|
||||||
|
|
||||||
|
// loading components from code split
|
||||||
|
// https://umijs.org/plugin/umi-plugin-react.html#dynamicimport
|
||||||
export default PageLoading;
|
export default PageLoading;
|
||||||
@ -3,7 +3,13 @@
|
|||||||
// 默认不播放动画,只有带animate类时才播放
|
// 默认不播放动画,只有带animate类时才播放
|
||||||
&.animate {
|
&.animate {
|
||||||
animation: pageEnter 0.5s cubic-bezier(0.4, 0, 0.2, 1);
|
animation: pageEnter 0.5s cubic-bezier(0.4, 0, 0.2, 1);
|
||||||
will-change: opacity, transform;
|
// 移除will-change避免HMR时样式冲突
|
||||||
|
// will-change: opacity, transform;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 动画结束后重置will-change,避免持续占用GPU资源
|
||||||
|
&.animate:not(:hover):not(:focus) {
|
||||||
|
animation-fill-mode: forwards;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -11,12 +17,12 @@
|
|||||||
from {
|
from {
|
||||||
opacity: 0;
|
opacity: 0;
|
||||||
transform: translateY(30px) scale(0.96);
|
transform: translateY(30px) scale(0.96);
|
||||||
filter: blur(4px);
|
// filter: blur(4px); // 注释掉filter属性,可能导致HMR问题
|
||||||
}
|
}
|
||||||
to {
|
to {
|
||||||
opacity: 1;
|
opacity: 1;
|
||||||
transform: translateY(0) scale(1);
|
transform: translateY(0) scale(1);
|
||||||
filter: blur(0);
|
// filter: blur(0); // 注释掉filter属性
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -41,7 +41,7 @@ const PageTransition: React.FC<PageTransitionProps> = ({
|
|||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
// 简化版本 - 仅使用CSS动画
|
// 简化版本 - 禁用所有动画
|
||||||
export const SimplePageTransition: React.FC<{
|
export const SimplePageTransition: React.FC<{
|
||||||
children: React.ReactNode;
|
children: React.ReactNode;
|
||||||
className?: string;
|
className?: string;
|
||||||
@ -50,23 +50,28 @@ export const SimplePageTransition: React.FC<{
|
|||||||
}> = ({
|
}> = ({
|
||||||
children,
|
children,
|
||||||
className = '',
|
className = '',
|
||||||
enableAnimation = true,
|
enableAnimation = false, // 强制禁用动画
|
||||||
onAnimationEnd,
|
onAnimationEnd,
|
||||||
}) => {
|
}) => {
|
||||||
|
// 立即执行回调,不等待动画
|
||||||
const handleAnimationEnd = () => {
|
const handleAnimationEnd = () => {
|
||||||
if (enableAnimation && onAnimationEnd) {
|
if (onAnimationEnd) {
|
||||||
onAnimationEnd();
|
onAnimationEnd();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// 立即执行动画结束回调
|
||||||
|
React.useEffect(() => {
|
||||||
|
if (onAnimationEnd) {
|
||||||
|
onAnimationEnd();
|
||||||
|
}
|
||||||
|
}, [onAnimationEnd]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div
|
<div className={`simple-page-transition ${className}`}>
|
||||||
className={`simple-page-transition ${enableAnimation ? 'animate' : ''} ${className}`}
|
|
||||||
onAnimationEnd={handleAnimationEnd}
|
|
||||||
>
|
|
||||||
{children}
|
{children}
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
export default PageTransition;
|
export default PageTransition;
|
||||||
@ -1,5 +1,4 @@
|
|||||||
// @import '~antd/es/style/themes/default.less';
|
@import '~antd/es/style/themes/default.less';
|
||||||
@import '~antd/dist/antd.less';
|
|
||||||
|
|
||||||
html,
|
html,
|
||||||
body,
|
body,
|
||||||
@ -25,51 +24,6 @@ body {
|
|||||||
-moz-osx-font-smoothing: grayscale;
|
-moz-osx-font-smoothing: grayscale;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 骨架屏优化样式
|
|
||||||
.ant-skeleton {
|
|
||||||
.ant-skeleton-content {
|
|
||||||
|
|
||||||
.ant-skeleton-title,
|
|
||||||
.ant-skeleton-paragraph>li {
|
|
||||||
background: linear-gradient(90deg, #f2f2f2 25%, #e6e6e6 50%, #f2f2f2 75%);
|
|
||||||
background-size: 200% 100%;
|
|
||||||
animation: loading 1.4s ease-in-out infinite;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.ant-skeleton-avatar {
|
|
||||||
background: linear-gradient(90deg, #f2f2f2 25%, #e6e6e6 50%, #f2f2f2 75%);
|
|
||||||
background-size: 200% 100%;
|
|
||||||
animation: loading 1.4s ease-in-out infinite;
|
|
||||||
}
|
|
||||||
|
|
||||||
.ant-skeleton-input,
|
|
||||||
.ant-skeleton-button {
|
|
||||||
background: linear-gradient(90deg, #f2f2f2 25%, #e6e6e6 50%, #f2f2f2 75%);
|
|
||||||
background-size: 200% 100%;
|
|
||||||
animation: loading 1.4s ease-in-out infinite;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@keyframes loading {
|
|
||||||
0% {
|
|
||||||
background-position: 200% 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
100% {
|
|
||||||
background-position: -200% 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 页面切换动画优化
|
|
||||||
.ant-layout-content {
|
|
||||||
transition: opacity 0.2s ease-in-out;
|
|
||||||
|
|
||||||
&.loading {
|
|
||||||
opacity: 0.7;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
ul,
|
ul,
|
||||||
ol {
|
ol {
|
||||||
list-style: none;
|
list-style: none;
|
||||||
@ -102,17 +56,3 @@ ol {
|
|||||||
min-height: 100vh;
|
min-height: 100vh;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 页面过渡优化
|
|
||||||
* {
|
|
||||||
box-sizing: border-box;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 增强页面切换体验
|
|
||||||
.ant-tabs-content-holder {
|
|
||||||
overflow: hidden;
|
|
||||||
}
|
|
||||||
|
|
||||||
.ant-tabs-tabpane {
|
|
||||||
outline: none;
|
|
||||||
}
|
|
||||||
@ -1,5 +1,4 @@
|
|||||||
@import '~antd/es/style/themes/default.less';
|
@import '~antd/es/style/themes/default.less';
|
||||||
@import '../components/PageTransition/index.less';
|
|
||||||
|
|
||||||
.ant-pro-global-header {
|
.ant-pro-global-header {
|
||||||
box-shadow: none !important;
|
box-shadow: none !important;
|
||||||
|
|||||||
@ -28,9 +28,6 @@ import * as Icon from '@ant-design/icons'
|
|||||||
import IconFont from '@/components/IconFont';
|
import IconFont from '@/components/IconFont';
|
||||||
import type { CurrentUser } from '@/models/user'
|
import type { CurrentUser } from '@/models/user'
|
||||||
import session from '@/utils/session';
|
import session from '@/utils/session';
|
||||||
import { SimplePageTransition } from '@/components/PageTransition';
|
|
||||||
import TabVirtualizer from '@/components/TabVirtualizer';
|
|
||||||
import { tabPerformanceManager, DEFAULT_CONFIG } from '@/utils/tabPerformanceManager';
|
|
||||||
import upMenu from '../assets/tab/upMenu.png'
|
import upMenu from '../assets/tab/upMenu.png'
|
||||||
import { getFieldEnum, getFieldEnumTravel, getFieldEnumTree, getFieldGetFieEnumList, getTravelFieldEnumTree, handleGetFieldEnumTreeTravel, handleGetNestingFIELDENUMList } from "@/services/options";
|
import { getFieldEnum, getFieldEnumTravel, getFieldEnumTree, getFieldGetFieEnumList, getTravelFieldEnumTree, handleGetFieldEnumTreeTravel, handleGetNestingFIELDENUMList } from "@/services/options";
|
||||||
import { handleGetServerpartTree } from '@/pages/basicManage/serverpartAssets/service';
|
import { handleGetServerpartTree } from '@/pages/basicManage/serverpartAssets/service';
|
||||||
@ -95,10 +92,7 @@ const BasicLayout: React.FC<BasicLayoutProps> = (props) => {
|
|||||||
|
|
||||||
|
|
||||||
const [activeKey, setActiveKey] = useState<string>(location?.pathname || '/')
|
const [activeKey, setActiveKey] = useState<string>(location?.pathname || '/')
|
||||||
const [animatedPages, setAnimatedPages] = useState<Set<string>>(new Set());
|
|
||||||
const [reloadingTabs, setReloadingTabs] = useState<Set<string>>(new Set());
|
|
||||||
const menuDataRef = useRef<MenuDataItem[]>([]);
|
const menuDataRef = useRef<MenuDataItem[]>([]);
|
||||||
const checkTimerRef = useRef<NodeJS.Timeout | null>(null);
|
|
||||||
const { formatMessage } = useIntl();
|
const { formatMessage } = useIntl();
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
@ -146,57 +140,13 @@ const BasicLayout: React.FC<BasicLayoutProps> = (props) => {
|
|||||||
// 改变panes
|
// 改变panes
|
||||||
const handleTabsPanes = (payload: any): void => {
|
const handleTabsPanes = (payload: any): void => {
|
||||||
if (dispatch) {
|
if (dispatch) {
|
||||||
// 检查是否为新页面(从未打开过的页面才需要动画)
|
|
||||||
const isNewPage = !tabsPanes.some(tab => tab.path === payload.path);
|
|
||||||
if (isNewPage) {
|
|
||||||
// 标记新页面需要播放动画
|
|
||||||
setAnimatedPages(prev => new Set(prev).add(payload.path));
|
|
||||||
}
|
|
||||||
|
|
||||||
// 更新访问时间
|
|
||||||
const updatedPayload = {
|
|
||||||
...payload,
|
|
||||||
lastAccessTime: Date.now(),
|
|
||||||
isLoaded: true,
|
|
||||||
isLoading: false,
|
|
||||||
};
|
|
||||||
|
|
||||||
dispatch({
|
dispatch({
|
||||||
type: 'global/changeTabsRoutes',
|
type: 'global/changeTabsRoutes',
|
||||||
payload: { data: updatedPayload, action: 'add' },
|
payload: { data: payload, action: 'add' },
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// 处理标签页重新加载
|
|
||||||
const handleTabReload = (tabPath: string): void => {
|
|
||||||
if (dispatch) {
|
|
||||||
// 标记为加载中
|
|
||||||
setReloadingTabs(prev => new Set(prev).add(tabPath));
|
|
||||||
|
|
||||||
// 重新加载时也要播放动画
|
|
||||||
setAnimatedPages(prev => new Set(prev).add(tabPath));
|
|
||||||
|
|
||||||
dispatch({
|
|
||||||
type: 'global/reloadTab',
|
|
||||||
payload: { tabPath },
|
|
||||||
});
|
|
||||||
|
|
||||||
// 模拟加载过程
|
|
||||||
setTimeout(() => {
|
|
||||||
setReloadingTabs(prev => {
|
|
||||||
const newSet = new Set(prev);
|
|
||||||
newSet.delete(tabPath);
|
|
||||||
return newSet;
|
|
||||||
});
|
|
||||||
|
|
||||||
// 切换到该标签页
|
|
||||||
history.push(tabPath);
|
|
||||||
setActiveKey(tabPath);
|
|
||||||
}, 800); // 800ms的加载时间
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
// 关闭当前标签
|
// 关闭当前标签
|
||||||
const handleEdit = (targetKey: string | React.MouseEvent<Element, MouseEvent> | React.KeyboardEvent<Element>, action: "add" | "remove"): void => {
|
const handleEdit = (targetKey: string | React.MouseEvent<Element, MouseEvent> | React.KeyboardEvent<Element>, action: "add" | "remove"): void => {
|
||||||
@ -210,13 +160,6 @@ const BasicLayout: React.FC<BasicLayoutProps> = (props) => {
|
|||||||
history.push(nextkey || '/')
|
history.push(nextkey || '/')
|
||||||
setActiveKey(nextkey)
|
setActiveKey(nextkey)
|
||||||
|
|
||||||
// 从动画记录中移除关闭的页面
|
|
||||||
setAnimatedPages(prev => {
|
|
||||||
const newSet = new Set(prev);
|
|
||||||
newSet.delete(targetKey as string);
|
|
||||||
return newSet;
|
|
||||||
});
|
|
||||||
|
|
||||||
// 缓存路由栈数据
|
// 缓存路由栈数据
|
||||||
dispatch({
|
dispatch({
|
||||||
type: 'global/changeTabsRoutes',
|
type: 'global/changeTabsRoutes',
|
||||||
@ -927,31 +870,6 @@ const BasicLayout: React.FC<BasicLayoutProps> = (props) => {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
// 启动标签页性能管理
|
|
||||||
useEffect(() => {
|
|
||||||
// 启动定时检查
|
|
||||||
checkTimerRef.current = setInterval(() => {
|
|
||||||
if (dispatch && tabsPanes.length > 0) {
|
|
||||||
const tabsToUnload = tabPerformanceManager.getTabsToUnload(tabsPanes, activeKey);
|
|
||||||
if (tabsToUnload.length > 0) {
|
|
||||||
// 批量卸载标签页
|
|
||||||
tabsToUnload.forEach(tabPath => {
|
|
||||||
dispatch({
|
|
||||||
type: 'global/unloadTab',
|
|
||||||
payload: { tabPath },
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}, DEFAULT_CONFIG.checkIntervalMinutes * 60 * 1000);
|
|
||||||
|
|
||||||
return () => {
|
|
||||||
if (checkTimerRef.current) {
|
|
||||||
clearInterval(checkTimerRef.current);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}, [dispatch, tabsPanes, activeKey]);
|
|
||||||
|
|
||||||
// 显示就调用
|
// 显示就调用
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
handleGetAllFieldEnum()
|
handleGetAllFieldEnum()
|
||||||
@ -1064,14 +982,6 @@ const BasicLayout: React.FC<BasicLayoutProps> = (props) => {
|
|||||||
onChange={(value) => {
|
onChange={(value) => {
|
||||||
history.push(value)
|
history.push(value)
|
||||||
setActiveKey(value)
|
setActiveKey(value)
|
||||||
|
|
||||||
// 更新标签页访问时间
|
|
||||||
if (dispatch) {
|
|
||||||
dispatch({
|
|
||||||
type: 'global/updateTabAccessTime',
|
|
||||||
payload: { tabPath: value },
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}}
|
}}
|
||||||
activeKey={activeKey}
|
activeKey={activeKey}
|
||||||
onEdit={handleEdit}
|
onEdit={handleEdit}
|
||||||
@ -1096,13 +1006,6 @@ const BasicLayout: React.FC<BasicLayoutProps> = (props) => {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 从动画记录中移除关闭的页面
|
|
||||||
setAnimatedPages(prev => {
|
|
||||||
const newSet = new Set(prev);
|
|
||||||
closeTabKeys.forEach(key => newSet.delete(key));
|
|
||||||
return newSet;
|
|
||||||
});
|
|
||||||
|
|
||||||
dispatch({
|
dispatch({
|
||||||
type: 'global/changeTabsRoutes',
|
type: 'global/changeTabsRoutes',
|
||||||
payload: { data: closeTabKeys, action: 'remove' },
|
payload: { data: closeTabKeys, action: 'remove' },
|
||||||
@ -1132,53 +1035,17 @@ const BasicLayout: React.FC<BasicLayoutProps> = (props) => {
|
|||||||
}
|
}
|
||||||
moreIcon={<DoubleRightOutlined style={{ color: "#7b828c" }} />}
|
moreIcon={<DoubleRightOutlined style={{ color: "#7b828c" }} />}
|
||||||
>
|
>
|
||||||
{tabsPanes && tabsPanes.map((item: tabsRoute) => {
|
{tabsPanes && tabsPanes.map((item: tabsRoute) =>
|
||||||
const shouldAnimate = animatedPages.has(item.path);
|
|
||||||
const isActive = activeKey === item.path;
|
|
||||||
const isLoaded = item.isLoaded !== false; // 默认为已加载状态
|
|
||||||
const isLoading = reloadingTabs.has(item.path) || item.isLoading === true;
|
|
||||||
|
|
||||||
return (
|
|
||||||
<TabPane
|
<TabPane
|
||||||
tab={item.title}
|
tab={item.title} key={item?.path}
|
||||||
key={item?.path}
|
style={{ padding: 24, paddingTop: 0 }}>
|
||||||
style={{ padding: 24, paddingTop: 0 }}
|
<Suspense fallback={<div>Loading...</div>}>
|
||||||
>
|
|
||||||
{/* 如果页面未加载或正在加载,显示TabVirtualizer */}
|
|
||||||
{(!isLoaded || isLoading) ? (
|
|
||||||
<TabVirtualizer
|
|
||||||
tabKey={item.path}
|
|
||||||
isActive={isActive}
|
|
||||||
isLoaded={isLoaded}
|
|
||||||
isLoading={isLoading}
|
|
||||||
lastAccessTime={item.lastAccessTime}
|
|
||||||
onReload={handleTabReload}
|
|
||||||
>
|
|
||||||
{/* 空内容,TabVirtualizer会处理显示 */}
|
|
||||||
</TabVirtualizer>
|
|
||||||
) : (
|
|
||||||
/* 页面已加载,直接显示内容,根据需要播放动画 */
|
|
||||||
<SimplePageTransition
|
|
||||||
enableAnimation={shouldAnimate}
|
|
||||||
onAnimationEnd={() => {
|
|
||||||
// 动画播放完成后,移除动画标记
|
|
||||||
setAnimatedPages(prev => {
|
|
||||||
const newSet = new Set(prev);
|
|
||||||
newSet.delete(item.path);
|
|
||||||
return newSet;
|
|
||||||
});
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<Suspense fallback={null}>
|
|
||||||
<Authorized authority={authorized!.authority} noMatch={noMatch}>
|
<Authorized authority={authorized!.authority} noMatch={noMatch}>
|
||||||
{item.children}
|
{item.children}
|
||||||
</Authorized>
|
</Authorized>
|
||||||
</Suspense>
|
</Suspense>
|
||||||
</SimplePageTransition>
|
</TabPane>)
|
||||||
)}
|
}
|
||||||
</TabPane>
|
|
||||||
);
|
|
||||||
})}
|
|
||||||
</Tabs>
|
</Tabs>
|
||||||
{/* 不要标签栏,删除tabs的代码,使用下方的代码就可以 */}
|
{/* 不要标签栏,删除tabs的代码,使用下方的代码就可以 */}
|
||||||
{/* <Authorized authority={authorized!.authority} noMatch={noMatch}>
|
{/* <Authorized authority={authorized!.authority} noMatch={noMatch}>
|
||||||
|
|||||||
@ -15,101 +15,68 @@ type SecurityLayoutProps = {
|
|||||||
|
|
||||||
type SecurityLayoutState = {
|
type SecurityLayoutState = {
|
||||||
isReady: boolean;
|
isReady: boolean;
|
||||||
shouldShowLoading: boolean;
|
|
||||||
initialLoadComplete: boolean;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
class SecurityLayout extends React.Component<SecurityLayoutProps, SecurityLayoutState> {
|
class SecurityLayout extends React.Component<SecurityLayoutProps, SecurityLayoutState> {
|
||||||
state: SecurityLayoutState = {
|
state: SecurityLayoutState = {
|
||||||
isReady: false,
|
isReady: false,
|
||||||
shouldShowLoading: false,
|
|
||||||
initialLoadComplete: false,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
private loadingTimer?: NodeJS.Timeout;
|
|
||||||
|
|
||||||
componentDidMount() {
|
componentDidMount() {
|
||||||
const { location } = history;
|
|
||||||
|
const { location } = history
|
||||||
|
|
||||||
const { dispatch } = this.props;
|
const { dispatch } = this.props;
|
||||||
|
|
||||||
// 检查是否有缓存的用户信息,避免不必要的加载状态
|
|
||||||
const cachedUser = session.get("currentUser");
|
|
||||||
|
|
||||||
// 设置防闪烁定时器,只有加载时间超过300ms才显示loading
|
|
||||||
this.loadingTimer = setTimeout(() => {
|
|
||||||
if (!this.state.isReady && !this.state.initialLoadComplete) {
|
|
||||||
this.setState({
|
|
||||||
shouldShowLoading: true,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}, 300);
|
|
||||||
|
|
||||||
if (dispatch) {
|
if (dispatch) {
|
||||||
|
|
||||||
dispatch({
|
dispatch({
|
||||||
type: 'user/fetch',
|
type: 'user/fetch', callback: (user) => {
|
||||||
callback: (user) => {
|
|
||||||
// 清除定时器
|
|
||||||
if (this.loadingTimer) {
|
|
||||||
clearTimeout(this.loadingTimer);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (user.code && location.pathname !== '/user/login') {
|
if (user.code && location.pathname !== '/user/login') {
|
||||||
history.push('/user/login');
|
history.push('/user/login');
|
||||||
return;
|
return
|
||||||
}
|
}
|
||||||
|
console.log('secur')
|
||||||
dispatch({
|
dispatch({
|
||||||
type: 'global/getMenuData',
|
type: 'global/getMenuData', payload: user.ID, callback: (menu) => {
|
||||||
payload: user.ID,
|
|
||||||
callback: (menu) => {
|
|
||||||
if (menu) {
|
if (menu) {
|
||||||
|
|
||||||
this.setState({
|
this.setState({
|
||||||
isReady: true,
|
isReady: true,
|
||||||
shouldShowLoading: false,
|
|
||||||
initialLoadComplete: true,
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
})
|
||||||
|
|
||||||
}
|
}
|
||||||
});
|
})
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
// 清除定时器
|
|
||||||
if (this.loadingTimer) {
|
|
||||||
clearTimeout(this.loadingTimer);
|
|
||||||
}
|
|
||||||
|
|
||||||
this.setState({
|
this.setState({
|
||||||
isReady: true,
|
isReady: true,
|
||||||
shouldShowLoading: false,
|
|
||||||
initialLoadComplete: true,
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
componentWillUnmount() {
|
|
||||||
if (this.loadingTimer) {
|
|
||||||
clearTimeout(this.loadingTimer);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
const { isReady, shouldShowLoading, initialLoadComplete } = this.state;
|
const { isReady } = this.state;
|
||||||
const { children, currentUser } = this.props;
|
const { children, loading, currentUser } = this.props;
|
||||||
|
// const { location } = history;
|
||||||
|
|
||||||
// 用户认证规则
|
|
||||||
|
// You can replace it to your authentication rule (such as check token exists)
|
||||||
|
// You can replace it with your own login authentication rules (such as judging whether the token exists)
|
||||||
const isLogin = currentUser && currentUser.ID;
|
const isLogin = currentUser && currentUser.ID;
|
||||||
|
|
||||||
// 如果初始化未完成且需要显示加载状态,才显示骨架屏
|
|
||||||
if (!isReady && shouldShowLoading) {
|
if ((!isLogin && loading) || !isReady) {
|
||||||
return <PageLoading />;
|
return <PageLoading />;
|
||||||
}
|
}
|
||||||
|
// if (!isLogin && location.pathname !== '/user/login') {
|
||||||
// 如果还在初始化过程中,但不需要显示loading,返回null(避免闪烁)
|
// history.push('/user/login');
|
||||||
if (!isReady && !shouldShowLoading) {
|
// }
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
return children;
|
return children;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -20,9 +20,6 @@ export type tabsRoute = {
|
|||||||
path: string;
|
path: string;
|
||||||
key: string;
|
key: string;
|
||||||
children: any;
|
children: any;
|
||||||
lastAccessTime?: number; // 最后访问时间
|
|
||||||
isLoaded?: boolean; // 是否已加载
|
|
||||||
isLoading?: boolean; // 是否正在加载
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export type GlobalModelState = {
|
export type GlobalModelState = {
|
||||||
@ -42,9 +39,6 @@ export type GlobalModelType = {
|
|||||||
changeNoticeReadState: Effect;
|
changeNoticeReadState: Effect;
|
||||||
changeTabsRoutes: Effect;
|
changeTabsRoutes: Effect;
|
||||||
getMenuData: Effect;
|
getMenuData: Effect;
|
||||||
updateTabAccessTime: Effect;
|
|
||||||
unloadTab: Effect;
|
|
||||||
reloadTab: Effect;
|
|
||||||
};
|
};
|
||||||
reducers: {
|
reducers: {
|
||||||
changeLayoutCollapsed: Reducer<GlobalModelState>;
|
changeLayoutCollapsed: Reducer<GlobalModelState>;
|
||||||
@ -185,26 +179,10 @@ const GlobalModel: GlobalModelType = {
|
|||||||
const index = state.global.tabsRoutes.findIndex(n => n.path === data.path)
|
const index = state.global.tabsRoutes.findIndex(n => n.path === data.path)
|
||||||
|
|
||||||
if (index === -1) { // 没缓存 则添加
|
if (index === -1) { // 没缓存 则添加
|
||||||
return [...state.global.tabsRoutes, {
|
return [...state.global.tabsRoutes, { ...data, index: state.global.tabsRoutes.length }]
|
||||||
...data,
|
|
||||||
index: state.global.tabsRoutes.length,
|
|
||||||
lastAccessTime: data.lastAccessTime || Date.now(),
|
|
||||||
isLoaded: data.isLoaded !== false,
|
|
||||||
isLoading: data.isLoading || false,
|
|
||||||
}]
|
|
||||||
}
|
}
|
||||||
// 否则更新现有标签页信息
|
// 否则不操作
|
||||||
return state.global.tabsRoutes.map(tab =>
|
return [...state.global.tabsRoutes]
|
||||||
tab.path === data.path
|
|
||||||
? {
|
|
||||||
...tab,
|
|
||||||
...data,
|
|
||||||
lastAccessTime: data.lastAccessTime || Date.now(),
|
|
||||||
isLoaded: data.isLoaded !== false,
|
|
||||||
isLoading: data.isLoading || false,
|
|
||||||
}
|
|
||||||
: tab
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
if (payload.action === 'removeAll') {
|
if (payload.action === 'removeAll') {
|
||||||
return []
|
return []
|
||||||
@ -221,57 +199,8 @@ const GlobalModel: GlobalModelType = {
|
|||||||
type: 'saveTabsRoutes',
|
type: 'saveTabsRoutes',
|
||||||
payload: tabsRoutes,
|
payload: tabsRoutes,
|
||||||
});
|
});
|
||||||
},
|
|
||||||
|
|
||||||
// 更新标签页访问时间
|
|
||||||
* updateTabAccessTime({ payload }, { put, select }) {
|
|
||||||
const { tabPath } = payload;
|
|
||||||
const tabsRoutes: tabsRoute[] = yield select((state: ConnectState) =>
|
|
||||||
state.global.tabsRoutes.map(tab =>
|
|
||||||
tab.path === tabPath
|
|
||||||
? { ...tab, lastAccessTime: Date.now(), isLoaded: true, isLoading: false }
|
|
||||||
: tab
|
|
||||||
)
|
|
||||||
);
|
|
||||||
|
|
||||||
yield put({
|
|
||||||
type: 'saveTabsRoutes',
|
|
||||||
payload: tabsRoutes,
|
|
||||||
});
|
|
||||||
},
|
|
||||||
|
|
||||||
// 卸载标签页
|
|
||||||
* unloadTab({ payload }, { put, select }) {
|
|
||||||
const { tabPath } = payload;
|
|
||||||
const tabsRoutes: tabsRoute[] = yield select((state: ConnectState) =>
|
|
||||||
state.global.tabsRoutes.map(tab =>
|
|
||||||
tab.path === tabPath
|
|
||||||
? { ...tab, isLoaded: false, isLoading: false }
|
|
||||||
: tab
|
|
||||||
)
|
|
||||||
);
|
|
||||||
|
|
||||||
yield put({
|
|
||||||
type: 'saveTabsRoutes',
|
|
||||||
payload: tabsRoutes,
|
|
||||||
});
|
|
||||||
},
|
|
||||||
|
|
||||||
// 重新加载标签页
|
|
||||||
* reloadTab({ payload }, { put, select }) {
|
|
||||||
const { tabPath } = payload;
|
|
||||||
const tabsRoutes: tabsRoute[] = yield select((state: ConnectState) =>
|
|
||||||
state.global.tabsRoutes.map(tab =>
|
|
||||||
tab.path === tabPath
|
|
||||||
? { ...tab, isLoaded: true, isLoading: false, lastAccessTime: Date.now() }
|
|
||||||
: tab
|
|
||||||
)
|
|
||||||
);
|
|
||||||
|
|
||||||
yield put({
|
|
||||||
type: 'saveTabsRoutes',
|
|
||||||
payload: tabsRoutes,
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user