From ec0ca11cc6ea05fd754b35c73b9a7bf583aab72f Mon Sep 17 00:00:00 2001 From: RuoYi Date: Sun, 22 Mar 2026 21:03:58 +0800 Subject: [PATCH] =?UTF-8?q?=E6=B7=BB=E5=8A=A0=E6=8C=81=E4=B9=85=E5=8C=96?= =?UTF-8?q?=E6=A0=87=E7=AD=BE=E9=A1=B5=E5=BC=80=E5=85=B3=E5=8A=9F=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/layout/components/Settings/index.vue | 20 ++++++++ .../src/layout/components/TagsView/index.vue | 5 +- ruoyi-ui/src/settings.js | 7 ++- ruoyi-ui/src/store/modules/settings.js | 3 +- ruoyi-ui/src/store/modules/tagsView.js | 47 +++++++++++++++++++ 5 files changed, 79 insertions(+), 3 deletions(-) diff --git a/ruoyi-ui/src/layout/components/Settings/index.vue b/ruoyi-ui/src/layout/components/Settings/index.vue index 1b21cb51..ff83c46a 100644 --- a/ruoyi-ui/src/layout/components/Settings/index.vue +++ b/ruoyi-ui/src/layout/components/Settings/index.vue @@ -65,6 +65,11 @@ +
+ 持久化标签页 + +
+
显示页签图标 @@ -125,6 +130,20 @@ export default { }) } }, + tagsViewPersist: { + get() { + return this.$store.state.settings.tagsViewPersist + }, + set(val) { + this.$store.dispatch('settings/changeSetting', { + key: 'tagsViewPersist', + value: val + }) + if (!val) { + this.$cache.local.remove('tags-view-visited') + } + } + }, tagsView: { get() { return this.$store.state.settings.tagsView @@ -237,6 +256,7 @@ export default { "navType":${this.navType}, "tagsView":${this.tagsView}, "tagsIcon":${this.tagsIcon}, + "tagsViewPersist":${this.tagsViewPersist}, "fixedHeader":${this.fixedHeader}, "sidebarLogo":${this.sidebarLogo}, "dynamicTitle":${this.dynamicTitle}, diff --git a/ruoyi-ui/src/layout/components/TagsView/index.vue b/ruoyi-ui/src/layout/components/TagsView/index.vue index 08a2be50..2a6b9ba5 100644 --- a/ruoyi-ui/src/layout/components/TagsView/index.vue +++ b/ruoyi-ui/src/layout/components/TagsView/index.vue @@ -177,10 +177,13 @@ export default { return tags }, initTags() { + if (this.$store.state.settings.tagsViewPersist) { + this.$store.dispatch('tagsView/loadPersistedViews') + } const affixTags = this.affixTags = this.filterAffixTags(this.routes) for (const tag of affixTags) { if (tag.name) { - this.$store.dispatch('tagsView/addVisitedView', tag) + this.$store.dispatch('tagsView/addAffixView', tag) } } }, diff --git a/ruoyi-ui/src/settings.js b/ruoyi-ui/src/settings.js index 97b40aa2..8f4b67c6 100644 --- a/ruoyi-ui/src/settings.js +++ b/ruoyi-ui/src/settings.js @@ -23,7 +23,12 @@ module.exports = { * 是否显示 tagsView */ tagsView: true, - + + /** + * 持久化标签页 + */ + tagsViewPersist: false, + /** * 显示页签图标 */ diff --git a/ruoyi-ui/src/store/modules/settings.js b/ruoyi-ui/src/store/modules/settings.js index 6aee6cd3..c4ce255c 100644 --- a/ruoyi-ui/src/store/modules/settings.js +++ b/ruoyi-ui/src/store/modules/settings.js @@ -1,7 +1,7 @@ import defaultSettings from '@/settings' import { useDynamicTitle } from '@/utils/dynamicTitle' -const { sideTheme, showSettings, navType, tagsView, tagsIcon, fixedHeader, sidebarLogo, dynamicTitle, footerVisible, footerContent } = defaultSettings +const { sideTheme, showSettings, navType, tagsView, tagsViewPersist, tagsIcon, fixedHeader, sidebarLogo, dynamicTitle, footerVisible, footerContent } = defaultSettings const storageSetting = JSON.parse(localStorage.getItem('layout-setting')) || '' const state = { @@ -11,6 +11,7 @@ const state = { showSettings: showSettings, navType: storageSetting.navType === undefined ? navType : storageSetting.navType, tagsView: storageSetting.tagsView === undefined ? tagsView : storageSetting.tagsView, + tagsViewPersist: storageSetting.tagsViewPersist === undefined ? tagsViewPersist : storageSetting.tagsViewPersist, tagsIcon: storageSetting.tagsIcon === undefined ? tagsIcon : storageSetting.tagsIcon, fixedHeader: storageSetting.fixedHeader === undefined ? fixedHeader : storageSetting.fixedHeader, sidebarLogo: storageSetting.sidebarLogo === undefined ? sidebarLogo : storageSetting.sidebarLogo, diff --git a/ruoyi-ui/src/store/modules/tagsView.js b/ruoyi-ui/src/store/modules/tagsView.js index 9a88c2bc..d3f52fb4 100644 --- a/ruoyi-ui/src/store/modules/tagsView.js +++ b/ruoyi-ui/src/store/modules/tagsView.js @@ -1,3 +1,26 @@ +import store from '@/store' +import cache from '@/plugins/cache' + +const PERSIST_KEY = 'tags-view-visited' + +function isPersistEnabled() { + return store.state.settings.tagsViewPersist +} + +function saveVisitedViews(views) { + if (!isPersistEnabled()) return + const toSave = views.filter(v => !(v.meta && v.meta.affix)).map(v => ({ path: v.path, fullPath: v.fullPath, name: v.name, title: v.title, query: v.query, meta: v.meta })) + cache.local.setJSON(PERSIST_KEY, toSave) +} + +function loadVisitedViews() { + return cache.local.getJSON(PERSIST_KEY) || [] +} + +function clearVisitedViews() { + cache.local.remove(PERSIST_KEY) +} + const state = { visitedViews: [], cachedViews: [], @@ -20,6 +43,15 @@ const mutations = { title: view.meta.title || 'no-name' }) ) + saveVisitedViews(state.visitedViews) + }, + ADD_VISITED_VIEW_FIRST: (state, view) => { + if (state.visitedViews.some(v => v.path === view.path)) return + state.visitedViews.unshift( + Object.assign({}, view, { + title: view.meta.title || 'no-name' + }) + ) }, ADD_CACHED_VIEW: (state, view) => { if (state.cachedViews.includes(view.name)) return @@ -35,6 +67,7 @@ const mutations = { } } state.iframeViews = state.iframeViews.filter(item => item.path !== view.path) + saveVisitedViews(state.visitedViews) }, DEL_IFRAME_VIEW: (state, view) => { state.iframeViews = state.iframeViews.filter(item => item.path !== view.path) @@ -49,6 +82,7 @@ const mutations = { return v.meta.affix || v.path === view.path }) state.iframeViews = state.iframeViews.filter(item => item.path === view.path) + saveVisitedViews(state.visitedViews) }, DEL_OTHERS_CACHED_VIEWS: (state, view) => { const index = state.cachedViews.indexOf(view.name) @@ -63,6 +97,7 @@ const mutations = { const affixTags = state.visitedViews.filter(tag => tag.meta.affix) state.visitedViews = affixTags state.iframeViews = [] + clearVisitedViews() }, DEL_ALL_CACHED_VIEWS: state => { state.cachedViews = [] @@ -94,6 +129,7 @@ const mutations = { } return false }) + saveVisitedViews(state.visitedViews) }, DEL_LEFT_VIEWS: (state, view) => { const index = state.visitedViews.findIndex(v => v.path === view.path) @@ -114,6 +150,7 @@ const mutations = { } return false }) + saveVisitedViews(state.visitedViews) } } @@ -128,6 +165,9 @@ const actions = { addVisitedView({ commit }, view) { commit('ADD_VISITED_VIEW', view) }, + addAffixView({ commit }, view) { + commit('ADD_VISITED_VIEW_FIRST', view) + }, addCachedView({ commit }, view) { commit('ADD_CACHED_VIEW', view) }, @@ -218,6 +258,13 @@ const actions = { resolve([...state.visitedViews]) }) }, + // 恢复持久化的 tags + loadPersistedViews({ commit }) { + const views = loadVisitedViews() + views.forEach(view => { + commit('ADD_VISITED_VIEW', view) + }) + }, } export default {