update 优化 优化快速点击页签刷新出现404问题

update 优化 优化页签全屏显示展示形式
This commit is contained in:
疯狂的狮子Li
2026-03-26 11:06:50 +08:00
parent 8469c254af
commit 05527965e2
2 changed files with 116 additions and 31 deletions
+112 -31
View File
@@ -39,7 +39,16 @@
<el-dropdown-item command="closeLeft" :disabled="isFirstView()">关闭左侧</el-dropdown-item> <el-dropdown-item command="closeLeft" :disabled="isFirstView()">关闭左侧</el-dropdown-item>
<el-dropdown-item command="closeRight" :disabled="isLastView()">关闭右侧</el-dropdown-item> <el-dropdown-item command="closeRight" :disabled="isLastView()">关闭右侧</el-dropdown-item>
<el-dropdown-item command="closeAll">全部关闭</el-dropdown-item> <el-dropdown-item command="closeAll">全部关闭</el-dropdown-item>
<el-dropdown-item command="fullscreen" divided>全屏显示</el-dropdown-item> <el-dropdown-item command="fullscreen" divided>
<template v-if="!isFullscreen">
<FullScreen />
<span>全屏显示</span>
</template>
<template v-else>
<CloseBold />
<span>退出全屏</span>
</template>
</el-dropdown-item>
</el-dropdown-menu> </el-dropdown-menu>
</template> </template>
</el-dropdown> </el-dropdown>
@@ -50,30 +59,18 @@
</span> </span>
<ul v-show="visible" :style="{ left: left + 'px', top: top + 'px' }" class="contextmenu"> <ul v-show="visible" :style="{ left: left + 'px', top: top + 'px' }" class="contextmenu">
<li @click="refreshSelectedTag(selectedTag)"> <li @click="refreshSelectedTag(selectedTag)"><RefreshRight style="width: 1em; height: 1em" /> 刷新页面</li>
<RefreshRight style="width: 1em; height: 1em" /> 刷新页面 <li v-if="!isAffix(selectedTag)" @click="closeSelectedTag(selectedTag)"><Close style="width: 1em; height: 1em" /> 关闭当前</li>
</li> <li @click="closeOthersTags"><CircleClose style="width: 1em; height: 1em" /> 关闭其他</li>
<li v-if="!isAffix(selectedTag)" @click="closeSelectedTag(selectedTag)"> <li v-if="!isFirstView()" @click="closeLeftTags"><Back style="width: 1em; height: 1em" /> 关闭左侧</li>
<Close style="width: 1em; height: 1em" /> 关闭当前 <li v-if="!isLastView()" @click="closeRightTags"><Right style="width: 1em; height: 1em" /> 关闭右侧</li>
</li> <li @click="closeAllTags(selectedTag)"><CircleClose style="width: 1em; height: 1em" /> 全部关闭</li>
<li @click="closeOthersTags">
<CircleClose style="width: 1em; height: 1em" /> 关闭其他
</li>
<li v-if="!isFirstView()" @click="closeLeftTags">
<Back style="width: 1em; height: 1em" /> 关闭左侧
</li>
<li v-if="!isLastView()" @click="closeRightTags">
<Right style="width: 1em; height: 1em" /> 关闭右侧
</li>
<li @click="closeAllTags(selectedTag)">
<CircleClose style="width: 1em; height: 1em" /> 全部关闭
</li>
</ul> </ul>
</div> </div>
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
import { ArrowDown, ArrowLeft, ArrowRight, Back, CircleClose, Close, RefreshRight, Right } from '@element-plus/icons-vue'; import { ArrowDown, ArrowLeft, ArrowRight, Back, CircleClose, Close, CloseBold, FullScreen, RefreshRight, Right } from '@element-plus/icons-vue';
import ScrollPane from './ScrollPane.vue'; import ScrollPane from './ScrollPane.vue';
import { getNormalPath } from '@/utils/ruoyi'; import { getNormalPath } from '@/utils/ruoyi';
import { useSettingsStore } from '@/store/modules/settings'; import { useSettingsStore } from '@/store/modules/settings';
@@ -90,6 +87,7 @@ const canScrollLeft = ref(false);
const canScrollRight = ref(false); const canScrollRight = ref(false);
const isFullscreen = ref(false); const isFullscreen = ref(false);
const scrollPaneRef = ref<InstanceType<typeof ScrollPane>>(); const scrollPaneRef = ref<InstanceType<typeof ScrollPane>>();
const fullscreenModeClass = 'tags-fullscreen-mode';
const { proxy } = getCurrentInstance() as ComponentInternalInstance; const { proxy } = getCurrentInstance() as ComponentInternalInstance;
const route = useRoute(); const route = useRoute();
@@ -334,17 +332,57 @@ const updateArrowState = () => {
}); });
}; };
const syncFullscreenLayout = () => {
if (!isFullscreen.value) {
return;
}
const mainContainer = document.querySelector('.main-container') as HTMLElement | null;
const layoutHeader = mainContainer?.querySelector('.layout-header') as HTMLElement | null;
if (!mainContainer || !layoutHeader) {
return;
}
const headerHeight = Math.ceil(layoutHeader.getBoundingClientRect().height);
mainContainer.style.setProperty('--tags-fullscreen-header-height', `${headerHeight}px`);
};
const enterFullscreenMode = async () => {
const mainContainer = document.querySelector('.main-container') as HTMLElement | null;
if (!mainContainer) {
return;
}
document.body.classList.add(fullscreenModeClass);
mainContainer.classList.add(fullscreenModeClass);
isFullscreen.value = true;
await nextTick();
syncFullscreenLayout();
};
const exitFullscreenMode = () => {
const mainContainer = document.querySelector('.main-container') as HTMLElement | null;
document.body.classList.remove(fullscreenModeClass);
mainContainer?.classList.remove(fullscreenModeClass);
mainContainer?.style.removeProperty('--tags-fullscreen-header-height');
document.querySelector<HTMLElement>('.tags-action-dropdown .tags-action-btn')?.blur();
isFullscreen.value = false;
};
const toggleFullscreen = async () => { const toggleFullscreen = async () => {
const appMain = document.querySelector('.app-main') as HTMLElement | null; if (isFullscreen.value) {
if (!document.fullscreenElement) { exitFullscreenMode();
await appMain?.requestFullscreen?.(); return;
} else { }
await document.exitFullscreen(); await enterFullscreenMode();
};
const handleKeyDown = (event: KeyboardEvent) => {
if (event.key === 'Escape' && isFullscreen.value) {
exitFullscreenMode();
} }
}; };
const onFullscreenChange = () => { const handleResize = () => {
isFullscreen.value = !!document.fullscreenElement; updateArrowState();
syncFullscreenLayout();
}; };
const handleDropdownCommand = (command: string) => { const handleDropdownCommand = (command: string) => {
@@ -397,13 +435,14 @@ onMounted(() => {
initTags(); initTags();
addTags(); addTags();
updateArrowState(); updateArrowState();
window.addEventListener('resize', updateArrowState); window.addEventListener('resize', handleResize);
document.addEventListener('fullscreenchange', onFullscreenChange); window.addEventListener('keydown', handleKeyDown);
}); });
onBeforeUnmount(() => { onBeforeUnmount(() => {
window.removeEventListener('resize', updateArrowState); exitFullscreenMode();
document.removeEventListener('fullscreenchange', onFullscreenChange); window.removeEventListener('resize', handleResize);
window.removeEventListener('keydown', handleKeyDown);
document.body.removeEventListener('click', closeMenu); document.body.removeEventListener('click', closeMenu);
}); });
</script> </script>
@@ -628,4 +667,46 @@ onBeforeUnmount(() => {
} }
} }
} }
body.tags-fullscreen-mode {
overflow: hidden;
}
body.tags-fullscreen-mode .drawer-bg,
body.tags-fullscreen-mode .sidebar-container,
body.tags-fullscreen-mode .navbar {
display: none !important;
}
.main-container.tags-fullscreen-mode {
position: fixed !important;
inset: 0 !important;
width: 100vw !important;
height: 100vh !important;
margin-left: 0 !important;
z-index: 2000;
overflow: hidden;
background: var(--app-shell-bg);
}
.main-container.tags-fullscreen-mode .layout-header {
gap: 0;
padding: 12px 12px 0;
}
.main-container.tags-fullscreen-mode .layout-header.fixed-header {
position: relative;
top: 0;
right: auto;
width: auto !important;
}
.main-container.tags-fullscreen-mode .app-main,
.main-container.tags-fullscreen-mode .app-main.with-fixed-header,
.main-container.tags-fullscreen-mode .app-main.with-fixed-header.with-tags-view {
height: calc(100vh - var(--tags-fullscreen-header-height, 50px));
min-height: calc(100vh - var(--tags-fullscreen-header-height, 50px)) !important;
padding-top: 12px !important;
overflow: auto;
}
</style> </style>
+4
View File
@@ -9,6 +9,10 @@ export default {
*/ */
async refreshPage(obj?: RouteLocationNormalized): Promise<void> { async refreshPage(obj?: RouteLocationNormalized): Promise<void> {
const { path, query, matched } = router.currentRoute.value; const { path, query, matched } = router.currentRoute.value;
// 防止在重定向过程中重复刷新
if (path.startsWith('/redirect/')) {
return Promise.resolve();
}
if (obj === undefined) { if (obj === undefined) {
matched.forEach((m: RouteLocationMatched) => { matched.forEach((m: RouteLocationMatched) => {
if (m.components && m.components.default && m.components.default.name) { if (m.components && m.components.default && m.components.default.name) {