- 新增产品管理相关路由和页面(dashboard、list、requirement、setting) - 实现产品基础信息编辑弹窗组件(base-info-dialog.vue) - 添加运行时字典功能(dict-select、dict-text、dict-tag组件) - 集成字典管理store和API调用 - 规范ID类型定义为string避免精度丢失问题 - 完善国际化资源文件支持中英文对照 - 新增对象上下文业务域入口页导航实现说明 - 添加Vue DevTools浮动入口注释说明 - 统一权限控制支持全局和对象作用域区分 - 规范分页查询参数类型定义与使用方式
321 lines
7.7 KiB
TypeScript
321 lines
7.7 KiB
TypeScript
import { computed, ref } from 'vue';
|
|
import { useEventListener } from '@vueuse/core';
|
|
import { defineStore } from 'pinia';
|
|
import type { RouteKey } from '@elegant-router/types';
|
|
import { useRouteStore } from '@/store/modules/route';
|
|
import { useRouterPush } from '@/hooks/common/router';
|
|
import { localStg } from '@/utils/storage';
|
|
import { getGlobalRouter } from '@/router/instance';
|
|
import { SetupStoreId } from '@/enum';
|
|
import { useThemeStore } from '../theme';
|
|
import {
|
|
extractTabsByAllRoutes,
|
|
filterTabsByIds,
|
|
findTabByRouteName,
|
|
getAllTabs,
|
|
getDefaultHomeTab,
|
|
getFixedTabIds,
|
|
getTabByRoute,
|
|
getTabIdByRoute,
|
|
isTabInTabs,
|
|
updateTabByI18nKey,
|
|
updateTabsByI18nKey
|
|
} from './shared';
|
|
|
|
export const useTabStore = defineStore(SetupStoreId.Tab, () => {
|
|
const routeStore = useRouteStore();
|
|
const themeStore = useThemeStore();
|
|
const { routerPush } = useRouterPush(false);
|
|
|
|
/** Tabs */
|
|
const tabs = ref<App.Global.Tab[]>([]);
|
|
|
|
/** Get active tab */
|
|
const homeTab = ref<App.Global.Tab>();
|
|
|
|
/** Init home tab */
|
|
function initHomeTab() {
|
|
homeTab.value = getDefaultHomeTab(getGlobalRouter(), routeStore.routeHome);
|
|
}
|
|
|
|
/** Get all tabs */
|
|
const allTabs = computed(() => getAllTabs(tabs.value, homeTab.value));
|
|
|
|
/** Active tab id */
|
|
const activeTabId = ref<string>('');
|
|
|
|
/**
|
|
* Set active tab id
|
|
*
|
|
* @param id Tab id
|
|
*/
|
|
function setActiveTabId(id: string) {
|
|
activeTabId.value = id;
|
|
}
|
|
|
|
/**
|
|
* Init tab store
|
|
*
|
|
* @param currentRoute Current route
|
|
*/
|
|
function initTabStore(currentRoute: App.Global.TabRoute) {
|
|
const storageTabs = localStg.get('globalTabs');
|
|
|
|
if (themeStore.tab.cache && storageTabs) {
|
|
const extractedTabs = extractTabsByAllRoutes(getGlobalRouter(), storageTabs);
|
|
tabs.value = updateTabsByI18nKey(extractedTabs);
|
|
}
|
|
|
|
addTab(currentRoute);
|
|
}
|
|
|
|
/**
|
|
* Add tab
|
|
*
|
|
* @param route Tab route
|
|
* @param active Whether to activate the added tab
|
|
*/
|
|
function addTab(route: App.Global.TabRoute, active = true) {
|
|
const tab = getTabByRoute(route);
|
|
|
|
const isHomeTab = tab.id === homeTab.value?.id;
|
|
|
|
if (!isHomeTab && !isTabInTabs(tab.id, tabs.value)) {
|
|
tabs.value.push(tab);
|
|
}
|
|
|
|
if (active) {
|
|
setActiveTabId(tab.id);
|
|
}
|
|
}
|
|
|
|
async function resetRemovedTabCaches(removedTabs: App.Global.Tab[], remainingTabs: App.Global.Tab[]) {
|
|
const routeKeysToReset = Array.from(
|
|
new Set(
|
|
removedTabs
|
|
.filter(tab => !remainingTabs.some(remainingTab => remainingTab.routeKey === tab.routeKey))
|
|
.map(tab => tab.routeKey)
|
|
)
|
|
);
|
|
|
|
await Promise.all(routeKeysToReset.map(routeKey => routeStore.resetRouteCache(routeKey)));
|
|
}
|
|
|
|
/**
|
|
* Remove tab when remove active tab, switch to next tab or home tab
|
|
*
|
|
* @param tabId Tab id
|
|
*/
|
|
async function removeTab(tabId: string) {
|
|
const removeTabIndex = tabs.value.findIndex(tab => tab.id === tabId);
|
|
if (removeTabIndex === -1) return;
|
|
|
|
const isRemoveActiveTab = activeTabId.value === tabId;
|
|
const removedTab = tabs.value[removeTabIndex];
|
|
|
|
// if remove the last tab, then switch to the second last tab
|
|
const nextTab = tabs.value[removeTabIndex + 1] || tabs.value[removeTabIndex - 1] || homeTab.value;
|
|
|
|
// remove tab
|
|
tabs.value.splice(removeTabIndex, 1);
|
|
|
|
// if current tab is removed, then switch to next tab
|
|
if (isRemoveActiveTab && nextTab) {
|
|
await switchRouteByTab(nextTab);
|
|
}
|
|
|
|
if (removedTab) {
|
|
await resetRemovedTabCaches([removedTab], tabs.value);
|
|
}
|
|
}
|
|
|
|
/** remove active tab */
|
|
async function removeActiveTab() {
|
|
await removeTab(activeTabId.value);
|
|
}
|
|
|
|
/**
|
|
* remove tab by route name
|
|
*
|
|
* @param routeName route name
|
|
*/
|
|
async function removeTabByRouteName(routeName: RouteKey) {
|
|
const tab = findTabByRouteName(routeName, tabs.value);
|
|
if (!tab) return;
|
|
|
|
await removeTab(tab.id);
|
|
}
|
|
|
|
/**
|
|
* Clear tabs
|
|
*
|
|
* @param excludes Exclude tab ids
|
|
*/
|
|
async function clearTabs(excludes: string[] = []) {
|
|
const remainTabIds = [...getFixedTabIds(tabs.value), ...excludes];
|
|
|
|
const tabsToRemove = tabs.value.filter(tab => !remainTabIds.includes(tab.id));
|
|
const removedTabsIds = tabsToRemove.map(tab => tab.id);
|
|
|
|
// If no tabs are actually being removed based on excludes and fixed tabs, exit
|
|
if (removedTabsIds.length === 0) {
|
|
return;
|
|
}
|
|
|
|
const isRemoveActiveTab = removedTabsIds.includes(activeTabId.value);
|
|
// filterTabsByIds returns tabs NOT in removedTabsIds, so these are the tabs that will remain
|
|
const updatedTabs = filterTabsByIds(removedTabsIds, tabs.value);
|
|
|
|
function update() {
|
|
tabs.value = updatedTabs;
|
|
}
|
|
|
|
if (isRemoveActiveTab) {
|
|
const activeTabCandidate = updatedTabs[updatedTabs.length - 1] || homeTab.value;
|
|
|
|
if (activeTabCandidate) {
|
|
// Ensure there's a tab to switch to
|
|
await switchRouteByTab(activeTabCandidate);
|
|
}
|
|
}
|
|
// Update the tabs array regardless of switch success or if a candidate was found
|
|
update();
|
|
|
|
await resetRemovedTabCaches(tabsToRemove, updatedTabs);
|
|
}
|
|
|
|
/**
|
|
* Switch route by tab
|
|
*
|
|
* @param tab
|
|
*/
|
|
async function switchRouteByTab(tab: App.Global.Tab) {
|
|
const fail = await routerPush(tab.fullPath);
|
|
if (!fail) {
|
|
setActiveTabId(tab.id);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Clear left tabs
|
|
*
|
|
* @param tabId
|
|
*/
|
|
async function clearLeftTabs(tabId: string) {
|
|
const tabIds = tabs.value.map(tab => tab.id);
|
|
const index = tabIds.indexOf(tabId);
|
|
if (index === -1) return;
|
|
|
|
const excludes = tabIds.slice(index);
|
|
await clearTabs(excludes);
|
|
}
|
|
|
|
/**
|
|
* Clear right tabs
|
|
*
|
|
* @param tabId
|
|
*/
|
|
async function clearRightTabs(tabId: string) {
|
|
const isHomeTab = tabId === homeTab.value?.id;
|
|
if (isHomeTab) {
|
|
clearTabs();
|
|
return;
|
|
}
|
|
|
|
const tabIds = tabs.value.map(tab => tab.id);
|
|
const index = tabIds.indexOf(tabId);
|
|
if (index === -1) return;
|
|
|
|
const excludes = tabIds.slice(0, index + 1);
|
|
await clearTabs(excludes);
|
|
}
|
|
|
|
/**
|
|
* Set new label of tab
|
|
*
|
|
* @default activeTabId
|
|
* @param label New tab label
|
|
* @param tabId Tab id
|
|
*/
|
|
function setTabLabel(label: string, tabId?: string) {
|
|
const id = tabId || activeTabId.value;
|
|
|
|
const tab = tabs.value.find(item => item.id === id);
|
|
if (!tab) return;
|
|
|
|
tab.oldLabel = tab.label;
|
|
tab.newLabel = label;
|
|
}
|
|
|
|
/**
|
|
* Reset tab label
|
|
*
|
|
* @default activeTabId
|
|
* @param tabId Tab id
|
|
*/
|
|
function resetTabLabel(tabId?: string) {
|
|
const id = tabId || activeTabId.value;
|
|
|
|
const tab = tabs.value.find(item => item.id === id);
|
|
if (!tab) return;
|
|
|
|
tab.newLabel = undefined;
|
|
}
|
|
|
|
/**
|
|
* Is tab retain
|
|
*
|
|
* @param tabId
|
|
*/
|
|
function isTabRetain(tabId: string) {
|
|
if (tabId === homeTab.value?.id) return true;
|
|
|
|
const fixedTabIds = getFixedTabIds(tabs.value);
|
|
|
|
return fixedTabIds.includes(tabId);
|
|
}
|
|
|
|
/** Update tabs by locale */
|
|
function updateTabsByLocale() {
|
|
tabs.value = updateTabsByI18nKey(tabs.value);
|
|
|
|
if (homeTab.value) {
|
|
homeTab.value = updateTabByI18nKey(homeTab.value);
|
|
}
|
|
}
|
|
|
|
/** Cache tabs */
|
|
function cacheTabs() {
|
|
if (!themeStore.tab.cache) return;
|
|
|
|
localStg.set('globalTabs', tabs.value);
|
|
}
|
|
|
|
// cache tabs when page is closed or refreshed
|
|
useEventListener(window, 'beforeunload', () => {
|
|
cacheTabs();
|
|
});
|
|
|
|
return {
|
|
/** All tabs */
|
|
tabs: allTabs,
|
|
activeTabId,
|
|
initHomeTab,
|
|
initTabStore,
|
|
addTab,
|
|
removeTab,
|
|
removeActiveTab,
|
|
removeTabByRouteName,
|
|
clearTabs,
|
|
clearLeftTabs,
|
|
clearRightTabs,
|
|
switchRouteByTab,
|
|
setTabLabel,
|
|
resetTabLabel,
|
|
isTabRetain,
|
|
updateTabsByLocale,
|
|
getTabIdByRoute,
|
|
cacheTabs
|
|
};
|
|
});
|