mirror of
https://github.com/soybeanjs/soybean-admin.git
synced 2025-09-27 05:36:43 +08:00
fix(projects): Tab automatically refreshed when switching to an iFrame Tab.
(cherry picked from commit 2c2759f8cc4333866bff9e392ed0bd7a9e933844)
This commit is contained in:
parent
222187d3b0
commit
eb1e0fcce2
@ -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>
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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,
|
||||
|
Loading…
Reference in New Issue
Block a user