update 优化 页签区增加左右滚动、右侧下拉、单独“刷新”按钮
add 新增 TagsView 全屏功能 add 新增 设置面板增加了“持久化标签页”开关 支持标签页持久化
This commit is contained in:
@@ -7,8 +7,8 @@ import { NavTypeEnum } from '@/enums/NavTypeEnum';
|
||||
|
||||
export const useSettingsStore = defineStore('setting', () => {
|
||||
const storageSetting = useStorage<LayoutSetting>('layout-setting', {
|
||||
topNav: defaultSettings.topNav,
|
||||
tagsView: defaultSettings.tagsView,
|
||||
tagsViewPersist: defaultSettings.tagsViewPersist,
|
||||
tagsIcon: defaultSettings.tagsIcon,
|
||||
fixedHeader: defaultSettings.fixedHeader,
|
||||
sidebarLogo: defaultSettings.sidebarLogo,
|
||||
@@ -22,6 +22,7 @@ export const useSettingsStore = defineStore('setting', () => {
|
||||
const sideTheme = ref<string>(storageSetting.value.sideTheme);
|
||||
const showSettings = ref<boolean>(defaultSettings.showSettings);
|
||||
const tagsView = ref<boolean>(storageSetting.value.tagsView);
|
||||
const tagsViewPersist = ref<boolean>(storageSetting.value.tagsViewPersist);
|
||||
const tagsIcon = ref<boolean>(storageSetting.value.tagsIcon);
|
||||
const fixedHeader = ref<boolean>(storageSetting.value.fixedHeader);
|
||||
const sidebarLogo = ref<boolean>(storageSetting.value.sidebarLogo);
|
||||
@@ -40,6 +41,7 @@ export const useSettingsStore = defineStore('setting', () => {
|
||||
sideTheme,
|
||||
showSettings,
|
||||
tagsView,
|
||||
tagsViewPersist,
|
||||
tagsIcon,
|
||||
fixedHeader,
|
||||
sidebarLogo,
|
||||
|
||||
+134
-28
@@ -1,17 +1,80 @@
|
||||
import { RouteLocationNormalized } from 'vue-router';
|
||||
import type { LocationQuery, RouteLocationNormalized, RouteMeta } from 'vue-router';
|
||||
import { defineStore } from 'pinia';
|
||||
import { ref } from 'vue';
|
||||
import { useSettingsStore } from './settings';
|
||||
|
||||
const PERSIST_KEY = 'tags-view-visited';
|
||||
|
||||
type PersistedTagView = {
|
||||
path: string;
|
||||
fullPath?: string;
|
||||
name?: string | symbol | null;
|
||||
title?: string;
|
||||
query?: LocationQuery;
|
||||
meta?: RouteMeta;
|
||||
};
|
||||
|
||||
type TagView = RouteLocationNormalized & {
|
||||
title?: string;
|
||||
};
|
||||
|
||||
const isPersistEnabled = () => {
|
||||
return useSettingsStore().tagsViewPersist;
|
||||
};
|
||||
|
||||
const normalizeVisitedView = (view: RouteLocationNormalized): TagView => {
|
||||
return Object.assign({}, view, {
|
||||
title: view.meta?.title || 'no-name'
|
||||
});
|
||||
};
|
||||
|
||||
const saveVisitedViews = (views: any[]) => {
|
||||
if (!isPersistEnabled()) {
|
||||
return;
|
||||
}
|
||||
|
||||
const payload: PersistedTagView[] = (views as TagView[])
|
||||
.filter((view) => !view.meta?.affix)
|
||||
.map((view) => ({
|
||||
path: view.path,
|
||||
fullPath: view.fullPath,
|
||||
name: view.name,
|
||||
title: (view as any).title || view.meta?.title || 'no-name',
|
||||
query: view.query,
|
||||
meta: view.meta
|
||||
}));
|
||||
|
||||
localStorage.setItem(PERSIST_KEY, JSON.stringify(payload));
|
||||
};
|
||||
|
||||
const loadVisitedViews = (): PersistedTagView[] => {
|
||||
const cache = localStorage.getItem(PERSIST_KEY);
|
||||
if (!cache) {
|
||||
return [];
|
||||
}
|
||||
|
||||
try {
|
||||
return JSON.parse(cache) as PersistedTagView[];
|
||||
} catch {
|
||||
localStorage.removeItem(PERSIST_KEY);
|
||||
return [];
|
||||
}
|
||||
};
|
||||
|
||||
const clearVisitedViews = () => {
|
||||
localStorage.removeItem(PERSIST_KEY);
|
||||
};
|
||||
|
||||
export const useTagsViewStore = defineStore('tagsView', () => {
|
||||
const visitedViews = ref<RouteLocationNormalized[]>([]);
|
||||
const visitedViews = ref<TagView[]>([]);
|
||||
const cachedViews = ref<string[]>([]);
|
||||
const iframeViews = ref<RouteLocationNormalized[]>([]);
|
||||
const iframeViews = ref<TagView[]>([]);
|
||||
|
||||
const getVisitedViews = (): RouteLocationNormalized[] => {
|
||||
return visitedViews.value as RouteLocationNormalized[];
|
||||
const getVisitedViews = (): TagView[] => {
|
||||
return visitedViews.value as TagView[];
|
||||
};
|
||||
const getIframeViews = (): RouteLocationNormalized[] => {
|
||||
return iframeViews.value as RouteLocationNormalized[];
|
||||
const getIframeViews = (): TagView[] => {
|
||||
return iframeViews.value as TagView[];
|
||||
};
|
||||
const getCachedViews = (): string[] => {
|
||||
return cachedViews.value;
|
||||
@@ -24,26 +87,54 @@ export const useTagsViewStore = defineStore('tagsView', () => {
|
||||
|
||||
const addIframeView = (view: RouteLocationNormalized): void => {
|
||||
if (iframeViews.value.some((v: RouteLocationNormalized) => v.path === view.path)) return;
|
||||
iframeViews.value.push(
|
||||
Object.assign({}, view, {
|
||||
title: view.meta?.title || 'no-name'
|
||||
})
|
||||
);
|
||||
iframeViews.value.push(normalizeVisitedView(view) as RouteLocationNormalized);
|
||||
};
|
||||
|
||||
const delIframeView = (view: RouteLocationNormalized): Promise<RouteLocationNormalized[]> => {
|
||||
return new Promise((resolve) => {
|
||||
iframeViews.value = iframeViews.value.filter((item: RouteLocationNormalized) => item.path !== view.path);
|
||||
resolve([...(iframeViews.value as RouteLocationNormalized[])]);
|
||||
resolve(iframeViews.value.slice() as RouteLocationNormalized[]);
|
||||
});
|
||||
};
|
||||
|
||||
const addVisitedView = (view: RouteLocationNormalized): void => {
|
||||
if (visitedViews.value.some((v: RouteLocationNormalized) => v.path === view.path)) return;
|
||||
visitedViews.value.push(
|
||||
Object.assign({}, view, {
|
||||
title: view.meta?.title || 'no-name'
|
||||
})
|
||||
);
|
||||
visitedViews.value.push(normalizeVisitedView(view));
|
||||
saveVisitedViews(visitedViews.value);
|
||||
};
|
||||
|
||||
const addAffixView = (view: RouteLocationNormalized): void => {
|
||||
if (visitedViews.value.some((v: RouteLocationNormalized) => v.path === view.path)) return;
|
||||
const insertIndex = visitedViews.value.findIndex((item) => !item.meta?.affix);
|
||||
const normalizedView = normalizeVisitedView(view);
|
||||
if (insertIndex === -1) {
|
||||
visitedViews.value.push(normalizedView);
|
||||
} else {
|
||||
visitedViews.value.splice(insertIndex, 0, normalizedView);
|
||||
}
|
||||
};
|
||||
|
||||
const loadPersistedViews = (): void => {
|
||||
loadVisitedViews().forEach((view) => {
|
||||
if (visitedViews.value.some((item) => item.path === view.path)) {
|
||||
return;
|
||||
}
|
||||
|
||||
visitedViews.value.push({
|
||||
hash: '',
|
||||
matched: [],
|
||||
params: {},
|
||||
redirectedFrom: undefined,
|
||||
path: view.path,
|
||||
fullPath: view.fullPath || view.path,
|
||||
query: view.query || {},
|
||||
name: view.name || undefined,
|
||||
meta: view.meta || {},
|
||||
title: view.title || view.meta?.title || 'no-name'
|
||||
} as TagView);
|
||||
});
|
||||
};
|
||||
|
||||
const delView = (
|
||||
view: RouteLocationNormalized
|
||||
): Promise<{
|
||||
@@ -56,7 +147,7 @@ export const useTagsViewStore = defineStore('tagsView', () => {
|
||||
delCachedView(view);
|
||||
}
|
||||
resolve({
|
||||
visitedViews: [...(visitedViews.value as RouteLocationNormalized[])],
|
||||
visitedViews: visitedViews.value.slice() as RouteLocationNormalized[],
|
||||
cachedViews: [...cachedViews.value]
|
||||
});
|
||||
});
|
||||
@@ -70,9 +161,11 @@ export const useTagsViewStore = defineStore('tagsView', () => {
|
||||
break;
|
||||
}
|
||||
}
|
||||
resolve([...(visitedViews.value as RouteLocationNormalized[])]);
|
||||
saveVisitedViews(visitedViews.value);
|
||||
resolve(visitedViews.value.slice() as RouteLocationNormalized[]);
|
||||
});
|
||||
};
|
||||
|
||||
const delCachedView = (view?: RouteLocationNormalized): Promise<string[]> => {
|
||||
let viewName = '';
|
||||
if (view) {
|
||||
@@ -84,6 +177,7 @@ export const useTagsViewStore = defineStore('tagsView', () => {
|
||||
resolve([...cachedViews.value]);
|
||||
});
|
||||
};
|
||||
|
||||
const delOthersViews = (
|
||||
view: RouteLocationNormalized
|
||||
): Promise<{
|
||||
@@ -94,7 +188,7 @@ export const useTagsViewStore = defineStore('tagsView', () => {
|
||||
delOthersVisitedViews(view);
|
||||
delOthersCachedViews(view);
|
||||
resolve({
|
||||
visitedViews: [...(visitedViews.value as RouteLocationNormalized[])],
|
||||
visitedViews: visitedViews.value.slice() as RouteLocationNormalized[],
|
||||
cachedViews: [...cachedViews.value]
|
||||
});
|
||||
});
|
||||
@@ -105,9 +199,11 @@ export const useTagsViewStore = defineStore('tagsView', () => {
|
||||
visitedViews.value = visitedViews.value.filter((v: RouteLocationNormalized) => {
|
||||
return v.meta?.affix || v.path === view.path;
|
||||
});
|
||||
resolve([...(visitedViews.value as RouteLocationNormalized[])]);
|
||||
saveVisitedViews(visitedViews.value);
|
||||
resolve(visitedViews.value.slice() as RouteLocationNormalized[]);
|
||||
});
|
||||
};
|
||||
|
||||
const delOthersCachedViews = (view: RouteLocationNormalized): Promise<string[]> => {
|
||||
const viewName = view.name as string;
|
||||
return new Promise((resolve) => {
|
||||
@@ -126,15 +222,17 @@ export const useTagsViewStore = defineStore('tagsView', () => {
|
||||
delAllVisitedViews();
|
||||
delAllCachedViews();
|
||||
resolve({
|
||||
visitedViews: [...(visitedViews.value as RouteLocationNormalized[])],
|
||||
visitedViews: visitedViews.value.slice() as RouteLocationNormalized[],
|
||||
cachedViews: [...cachedViews.value]
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
const delAllVisitedViews = (): Promise<RouteLocationNormalized[]> => {
|
||||
return new Promise((resolve) => {
|
||||
visitedViews.value = visitedViews.value.filter((tag: RouteLocationNormalized) => tag.meta?.affix);
|
||||
resolve([...(visitedViews.value as RouteLocationNormalized[])]);
|
||||
clearVisitedViews();
|
||||
resolve(visitedViews.value.slice() as RouteLocationNormalized[]);
|
||||
});
|
||||
};
|
||||
|
||||
@@ -152,11 +250,14 @@ export const useTagsViewStore = defineStore('tagsView', () => {
|
||||
break;
|
||||
}
|
||||
}
|
||||
saveVisitedViews(visitedViews.value);
|
||||
};
|
||||
|
||||
const delRightTags = (view: RouteLocationNormalized): Promise<RouteLocationNormalized[]> => {
|
||||
return new Promise((resolve) => {
|
||||
const index = visitedViews.value.findIndex((v: RouteLocationNormalized) => v.path === view.path);
|
||||
if (index === -1) {
|
||||
resolve(visitedViews.value.slice() as RouteLocationNormalized[]);
|
||||
return;
|
||||
}
|
||||
visitedViews.value = visitedViews.value.filter((item: RouteLocationNormalized, idx: number) => {
|
||||
@@ -169,13 +270,16 @@ export const useTagsViewStore = defineStore('tagsView', () => {
|
||||
}
|
||||
return false;
|
||||
});
|
||||
resolve([...(visitedViews.value as RouteLocationNormalized[])]);
|
||||
saveVisitedViews(visitedViews.value);
|
||||
resolve(visitedViews.value.slice() as RouteLocationNormalized[]);
|
||||
});
|
||||
};
|
||||
|
||||
const delLeftTags = (view: RouteLocationNormalized): Promise<RouteLocationNormalized[]> => {
|
||||
return new Promise((resolve) => {
|
||||
const index = visitedViews.value.findIndex((v: RouteLocationNormalized) => v.path === view.path);
|
||||
if (index === -1) {
|
||||
resolve(visitedViews.value.slice() as RouteLocationNormalized[]);
|
||||
return;
|
||||
}
|
||||
visitedViews.value = visitedViews.value.filter((item: RouteLocationNormalized, idx: number) => {
|
||||
@@ -188,7 +292,8 @@ export const useTagsViewStore = defineStore('tagsView', () => {
|
||||
}
|
||||
return false;
|
||||
});
|
||||
resolve([...(visitedViews.value as RouteLocationNormalized[])]);
|
||||
saveVisitedViews(visitedViews.value);
|
||||
resolve(visitedViews.value.slice() as RouteLocationNormalized[]);
|
||||
});
|
||||
};
|
||||
|
||||
@@ -202,7 +307,6 @@ export const useTagsViewStore = defineStore('tagsView', () => {
|
||||
};
|
||||
|
||||
const isDynamicRoute = (view: RouteLocationNormalized): boolean => {
|
||||
// 检查匹配的路由记录中是否有动态段
|
||||
return view.matched.some((m) => m.path.includes(':'));
|
||||
};
|
||||
|
||||
@@ -216,6 +320,7 @@ export const useTagsViewStore = defineStore('tagsView', () => {
|
||||
getCachedViews,
|
||||
|
||||
addVisitedView,
|
||||
addAffixView,
|
||||
addCachedView,
|
||||
delVisitedView,
|
||||
delCachedView,
|
||||
@@ -229,6 +334,7 @@ export const useTagsViewStore = defineStore('tagsView', () => {
|
||||
delRightTags,
|
||||
delLeftTags,
|
||||
addIframeView,
|
||||
delIframeView
|
||||
delIframeView,
|
||||
loadPersistedViews
|
||||
};
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user