fix(projects): Tab automatically refreshed when switching to an iFrame Tab.

(cherry picked from commit 2c2759f8cc4333866bff9e392ed0bd7a9e933844)
This commit is contained in:
SkiffBoy 2025-06-04 08:08:05 +08:00
parent 222187d3b0
commit eb1e0fcce2
3 changed files with 132 additions and 3 deletions

View File

@ -1,6 +1,9 @@
<script setup lang="ts">
import { computed } from 'vue';
import type { VNode } from 'vue';
import { computed, defineAsyncComponent, reactive, shallowRef, watch } from 'vue';
import type { RouteRecordRaw } from 'vue-router';
import { LAYOUT_SCROLL_EL_ID } from '@sa/materials';
import { router as globalRouter } from '@/router';
import { useAppStore } from '@/store/modules/app';
import { useThemeStore } from '@/store/modules/theme';
import { useRouteStore } from '@/store/modules/route';
@ -31,6 +34,63 @@ function resetScroll() {
el?.scrollTo({ left: 0, top: 0 });
}
function isIframeComponent(component: VNode) {
const extraProps = { ...(component.type as Record<string, any>) };
return extraProps.name === 'iframe-page';
}
// Cache the loaded iFrame components
const iFrameComponentCache = shallowRef<Map<string, any>>(new Map());
const iFrameTabReloadFlags = reactive(
routeStore.iFrameRoutes.reduce((tabReloadFlagMap, route) => {
tabReloadFlagMap.set(route.name, appStore.reloadFlag);
return tabReloadFlagMap;
}, new Map())
);
function iframeComponent(route: RouteRecordRaw) {
const routeName = `${route?.name?.toString()}`;
if (route?.name && !iFrameComponentCache.value.get(routeName)) {
if (typeof route.component === 'function') {
const component = defineAsyncComponent(route.component as () => Promise<any>);
iFrameComponentCache.value.set(routeName, component);
}
}
return iFrameComponentCache.value.get(routeName);
}
// Calculate the list of iFrame components that need to be show
const visibleIFrames = computed(() => {
return routeStore.iFrameRoutes.filter(
route =>
globalRouter.currentRoute.value.name === route.name ||
iFrameComponentCache.value.get(`${route?.name?.toString()}`)
);
});
// Listen for route changes and load iFrame components as needed
watch(
() => globalRouter.currentRoute.value,
newRoute => {
routeStore.iFrameRoutes.forEach(route => {
if (newRoute.name === route.name && !iFrameComponentCache.value.get(`${route?.name?.toString()}`)) {
iframeComponent(route);
}
});
},
{ immediate: true }
);
// Listens for refresh operations and refreshes only the current iFrame component
watch(
() => appStore.reloadFlag,
reloadFlag => {
const tabKey = globalRouter.currentRoute.value.name;
iFrameTabReloadFlags.set(tabKey, reloadFlag);
},
{ immediate: true }
);
</script>
<template>
@ -45,7 +105,7 @@ function resetScroll() {
<KeepAlive :include="routeStore.cacheRoutes" :exclude="routeStore.excludeCacheRoutes">
<component
:is="Component"
v-if="appStore.reloadFlag"
v-if="appStore.reloadFlag && !isIframeComponent(Component)"
:key="tabStore.getTabIdByRoute(route)"
:class="{ 'p-16px': showPadding }"
class="flex-grow bg-layout transition-300"
@ -53,6 +113,17 @@ function resetScroll() {
</KeepAlive>
</Transition>
</RouterView>
<template v-for="route in visibleIFrames" :key="route.name">
<component
:is="iframeComponent(route)"
v-show="globalRouter.currentRoute.value.name === route.name"
v-if="iFrameTabReloadFlags.get(route.name)"
v-bind="route?.props as Record<string, any>"
:class="{ 'p-8px': showPadding }"
class="flex-grow bg-layout transition-300"
/>
</template>
</template>
<style></style>

View File

@ -38,3 +38,22 @@ export function createStaticRoutes() {
export function getAuthVueRoutes(routes: ElegantConstRoute[]) {
return transformElegantRoutesToVueRoutes(routes, layouts, views);
}
/**
* Get iFrame route names
*
* @param routes
*/
export function getIframeRouteNames(routes: ElegantConstRoute[]) {
const routeNames = [] as string[];
routes.forEach(route => {
if (route.component?.indexOf('view.iframe-page') !== -1 && route.props && route.name !== 'iframe-page') {
routeNames.push(route.name);
}
if (route.children?.length) {
const childNames = getIframeRouteNames(route.children);
routeNames.push(...childNames);
}
});
return routeNames;
}

View File

@ -6,7 +6,7 @@ import type { CustomRoute, ElegantConstRoute, LastLevelRouteKey, RouteKey, Route
import { router } from '@/router';
import { fetchGetConstantRoutes, fetchGetUserRoutes, fetchIsRouteExist } from '@/service/api';
import { SetupStoreId } from '@/enum';
import { createStaticRoutes, getAuthVueRoutes } from '@/router/routes';
import { createStaticRoutes, getAuthVueRoutes, getIframeRouteNames } from '@/router/routes';
import { ROOT_ROUTE } from '@/router/routes/builtin';
import { getRouteName, getRoutePath } from '@/router/elegant/transform';
import { useAuthStore } from '../auth';
@ -41,6 +41,9 @@ export const useRouteStore = defineStore(SetupStoreId.Route, () => {
/** Home route key */
const routeHome = ref(import.meta.env.VITE_ROUTE_HOME);
/** iFrame Vue Routes */
const iFrameRoutes = shallowRef<RouteRecordRaw[]>([]);
/**
* Set route home
*
@ -111,6 +114,20 @@ export const useRouteStore = defineStore(SetupStoreId.Route, () => {
cacheRoutes.value = getCacheRouteNames(routes);
}
/**
* Get iFrame routes
*
* @param routes Vue routes
*/
function getIFrameRoutes(vueRoutes: RouteRecordRaw[], routes: ElegantConstRoute[]) {
const iframeRouteNames = getIframeRouteNames(routes);
const iframe = cacheRoutes.value.indexOf('iframe-page' as RouteKey);
if (iframe > -1) {
cacheRoutes.value.splice(iframe, 1);
}
iFrameRoutes.value = filterIframeRoutesByName(vueRoutes, iframeRouteNames);
}
/**
* Reset route cache
*
@ -244,6 +261,8 @@ export const useRouteStore = defineStore(SetupStoreId.Route, () => {
getGlobalMenus(sortRoutes);
getCacheRoutes(vueRoutes);
getIFrameRoutes(vueRoutes, sortRoutes);
}
/**
@ -258,6 +277,25 @@ export const useRouteStore = defineStore(SetupStoreId.Route, () => {
});
}
/**
* Get iFrame routes by route names
*
* @param vueRoutes
* @param iframeRouteNames
*/
function filterIframeRoutesByName(vueRoutes: RouteRecordRaw[], iframeRouteNames: string[]) {
return vueRoutes.reduce((values, route) => {
let result = [...values];
if (route.children?.length) {
result = result.concat(filterIframeRoutesByName(route.children, iframeRouteNames));
}
if (route.name && iframeRouteNames.includes(route.name.toString())) {
result.unshift(route);
}
return result;
}, [] as RouteRecordRaw[]);
}
/**
* Add remove route fn
*
@ -332,6 +370,7 @@ export const useRouteStore = defineStore(SetupStoreId.Route, () => {
searchMenus,
updateGlobalMenusByLocale,
cacheRoutes,
iFrameRoutes,
excludeCacheRoutes,
resetRouteCache,
breadcrumbs,