feat(product): 新增产品管理模块与字典组件功能

- 新增产品管理相关路由和页面(dashboard、list、requirement、setting)
- 实现产品基础信息编辑弹窗组件(base-info-dialog.vue)
- 添加运行时字典功能(dict-select、dict-text、dict-tag组件)
- 集成字典管理store和API调用
- 规范ID类型定义为string避免精度丢失问题
- 完善国际化资源文件支持中英文对照
- 新增对象上下文业务域入口页导航实现说明
- 添加Vue DevTools浮动入口注释说明
- 统一权限控制支持全局和对象作用域区分
- 规范分页查询参数类型定义与使用方式
This commit is contained in:
2026-04-23 09:05:55 +08:00
parent c5911ea34b
commit 4122dfa50d
95 changed files with 9581 additions and 801 deletions

View File

@@ -2,8 +2,8 @@ import { effectScope, nextTick, onScopeDispose, ref, watch } from 'vue';
import { breakpointsTailwind, useBreakpoints, useEventListener, useTitle } from '@vueuse/core';
import { defineStore } from 'pinia';
import { useBoolean } from '@sa/hooks';
import { router } from '@/router';
import { localStg } from '@/utils/storage';
import { getGlobalRouter } from '@/router/instance';
import { SetupStoreId } from '@/enum';
import { $t, setLocale } from '@/locales';
import { setDayjsLocale } from '@/locales/dayjs';
@@ -63,7 +63,7 @@ export const useAppStore = defineStore(SetupStoreId.App, () => {
/** Update document title by locale */
function updateDocumentTitleByLocale() {
const { i18nKey, title } = router.currentRoute.value.meta;
const { i18nKey, title } = getGlobalRouter().currentRoute.value.meta;
const documentTitle = i18nKey ? $t(i18nKey) : title;

View File

@@ -7,8 +7,10 @@ import { useRouterPush } from '@/hooks/common/router';
import { localStg } from '@/utils/storage';
import { SetupStoreId } from '@/enum';
import { $t } from '@/locales';
import { useDictStore } from '../dict';
import { useRouteStore } from '../route';
import { useTabStore } from '../tab';
import { useObjectContextStore } from '../object-context';
import { clearAuthStorage, getToken } from './shared';
export const useAuthStore = defineStore(SetupStoreId.Auth, () => {
@@ -16,6 +18,8 @@ export const useAuthStore = defineStore(SetupStoreId.Auth, () => {
const authStore = useAuthStore();
const routeStore = useRouteStore();
const tabStore = useTabStore();
const dictStore = useDictStore();
const objectContextStore = useObjectContextStore();
const { toLogin, redirectFromLogin } = useRouterPush(false);
const { loading: loginLoading, startLoading, endLoading } = useLoading();
@@ -46,6 +50,8 @@ export const useAuthStore = defineStore(SetupStoreId.Auth, () => {
clearAuthStorage();
authStore.$reset();
dictStore.resetDictCache();
objectContextStore.$reset();
if (!route.meta.constant) {
await toLogin();
@@ -138,6 +144,8 @@ export const useAuthStore = defineStore(SetupStoreId.Auth, () => {
const pass = await getUserInfo();
if (pass) {
await dictStore.initDictCache(true);
token.value = loginToken.token;
return true;

View File

@@ -0,0 +1,210 @@
import { ref } from 'vue';
import { defineStore } from 'pinia';
import { RDMS_OBJECT_DIRECTION_DICT_CODE, RDMS_OBJECT_DIRECTION_LEGACY_DICT_CODE } from '@/constants/dict';
import { fetchGetFrontendDictCache } from '@/service/api';
import { SetupStoreId } from '@/enum';
type DictValue = string | number | null | undefined;
type DictFilterOptions = {
onlyEnabled?: boolean;
};
type DictLabelOptions = DictFilterOptions & {
fallback?: string;
};
type DictLabelsOptions = DictLabelOptions & {
separator?: string;
};
function sortDictData(list: Api.Dict.DictData[]) {
return list.slice().sort((left, right) => left.sort - right.sort || left.label.localeCompare(right.label, 'zh-CN'));
}
function normalizeFrontendDictData(
dictType: string,
list: Api.Dict.FrontendDictData[],
dictIndex: number
): Api.Dict.DictData[] {
const normalizedList = list.map((item, itemIndex) => ({
id: -((dictIndex + 1) * 100000 + itemIndex + 1),
label: item.label,
value: item.value,
dictType: item.dictType || dictType,
sort: item.sort,
status: item.status ?? 0,
remark: null,
createTime: 0
}));
return sortDictData(normalizedList);
}
function normalizeFrontendDictCache(cache: Api.Dict.FrontendDictCache) {
const entries = Object.entries(cache);
return Object.fromEntries(
entries.map(([dictType, list], index) => [dictType, normalizeFrontendDictData(dictType, list, index)])
);
}
function applyDictTypeAliases(dictDataMap: Record<string, Api.Dict.DictData[]>) {
const nextDictDataMap = { ...dictDataMap };
// 兼容后端尚未切换完成的过渡期:旧编码仍返回时,前端统一映射到新编码。
if (!nextDictDataMap[RDMS_OBJECT_DIRECTION_DICT_CODE] && nextDictDataMap[RDMS_OBJECT_DIRECTION_LEGACY_DICT_CODE]) {
nextDictDataMap[RDMS_OBJECT_DIRECTION_DICT_CODE] = nextDictDataMap[RDMS_OBJECT_DIRECTION_LEGACY_DICT_CODE].map(
item => ({
...item,
dictType: RDMS_OBJECT_DIRECTION_DICT_CODE
})
);
}
return nextDictDataMap;
}
function createRuntimeDictTypes(dictDataMap: Record<string, Api.Dict.DictData[]>) {
return Object.keys(dictDataMap).map((dictType, index) => ({
id: -(index + 1),
name: dictType,
type: dictType,
status: 0 as const,
remark: null,
createTime: 0
}));
}
function findDictItem(list: Api.Dict.DictData[], value?: DictValue) {
if (value === null || value === undefined || value === '') {
return undefined;
}
return list.find(item => item.value === String(value));
}
export const useDictStore = defineStore(SetupStoreId.Dict, () => {
const loading = ref(false);
const initialized = ref(false);
const dictTypes = ref<Api.Dict.DictType[]>([]);
const dictDataMap = ref<Record<string, Api.Dict.DictData[]>>({});
const loadedAt = ref<number | null>(null);
let initPromise: Promise<boolean> | null = null;
function resetDictCache() {
dictTypes.value = [];
dictDataMap.value = {};
loadedAt.value = null;
initialized.value = false;
initPromise = null;
}
async function initDictCache(force = false) {
if (initialized.value && !force) {
return true;
}
if (initPromise && !force) {
return initPromise;
}
if (force) {
resetDictCache();
}
initPromise = (async () => {
loading.value = true;
const result = await fetchGetFrontendDictCache();
loading.value = false;
if (result.error) {
initPromise = null;
return false;
}
const normalizedDictDataMap = applyDictTypeAliases(normalizeFrontendDictCache(result.data || {}));
dictTypes.value = createRuntimeDictTypes(normalizedDictDataMap);
dictDataMap.value = normalizedDictDataMap;
loadedAt.value = Date.now();
initialized.value = true;
initPromise = null;
return true;
})();
return initPromise;
}
function getDictData(dictType: string, onlyEnabled = false) {
if (!dictType) {
return [];
}
const list = dictDataMap.value[dictType] || [];
if (!onlyEnabled) {
return list;
}
return list.filter(item => item.status === 0);
}
function getDictOptions(dictType: string, onlyEnabled = true) {
return getDictData(dictType, onlyEnabled).map(item => ({
label: item.label,
value: item.value
}));
}
function getDictItem(dictType: string, value?: DictValue, options: DictFilterOptions = {}) {
return findDictItem(getDictData(dictType, options.onlyEnabled), value);
}
function getDictLabel(dictType: string, value?: DictValue, options: DictLabelOptions = {}) {
const { fallback = '--', onlyEnabled = false } = options;
if (value === null || value === undefined || value === '') {
return fallback;
}
const matched = getDictItem(dictType, value, { onlyEnabled });
return matched?.label || String(value);
}
function getDictLabels(dictType: string, values?: Array<DictValue> | null, options: DictLabelsOptions = {}) {
const { fallback = '--', separator = ' / ', onlyEnabled = false } = options;
if (!values?.length) {
return fallback;
}
const labels = values
.filter(value => value !== null && value !== undefined && value !== '')
.map(value => getDictLabel(dictType, value, { fallback: String(value), onlyEnabled }));
return labels.length ? labels.join(separator) : fallback;
}
function hasDictValue(dictType: string, value?: DictValue, options: DictFilterOptions = {}) {
return Boolean(getDictItem(dictType, value, options));
}
return {
loading,
initialized,
dictTypes,
dictDataMap,
loadedAt,
initDictCache,
resetDictCache,
getDictData,
getDictOptions,
getDictItem,
getDictLabel,
getDictLabels,
hasDictValue
};
});

View File

@@ -0,0 +1,403 @@
import { computed, ref } from 'vue';
import type { LocationQueryRaw, RouteLocationNormalized, RouteLocationRaw } from 'vue-router';
import { defineStore } from 'pinia';
import type { ElegantConstRoute } from '@elegant-router/types';
import {
OBJECT_CONTEXT_QUERY_KEY,
getObjectContextDomainConfigByPath,
isObjectContextEntryPath
} from '@/constants/object-context';
import { fetchGetObjectContext } from '@/service/api/object-context';
import { $t } from '@/locales';
import { SetupStoreId } from '@/enum';
import { useRouteStore } from '../route';
function createEmptyState(): App.ObjectContext.State {
return {
domainKey: '',
objectType: '',
objectId: '',
objectName: '',
objectSummary: null,
contextScopedMenus: [],
buttonCodes: [],
defaultRouteKey: '',
defaultRoutePath: '',
isReady: false
};
}
function normalizePath(path: string) {
if (!path) {
return '/';
}
return path.endsWith('/') && path !== '/' ? path.slice(0, -1) : path;
}
function isRouteMatchedByPrefix(path: string, prefix: string) {
const normalizedPath = normalizePath(path);
const normalizedPrefix = normalizePath(prefix);
return normalizedPath === normalizedPrefix || normalizedPath.startsWith(`${normalizedPrefix}/`);
}
function findDomainRootRoute(
routes: ElegantConstRoute[],
config: App.ObjectContext.DomainConfig
): ElegantConstRoute | null {
for (const route of routes) {
if (config.routePathPrefixes.some(prefix => isRouteMatchedByPrefix(route.path, prefix))) {
return route;
}
if (route.children?.length) {
const matchedChild = findDomainRootRoute(route.children, config);
if (matchedChild) {
return matchedChild;
}
}
}
return null;
}
function isEntryRoute(route: ElegantConstRoute, config: App.ObjectContext.DomainConfig) {
return route.name === config.entryRouteKey || normalizePath(route.path) === normalizePath(config.entryRoutePath);
}
function getContextMenuLabel(route: ElegantConstRoute) {
const routeName = String(route.name || route.path);
return route.meta?.i18nKey ? $t(route.meta.i18nKey) : String(route.meta?.title || routeName);
}
type ContextRouteLookupItem = {
key: string;
label: string;
routeKey: string | null;
routePath: string | null;
};
function createContextRouteLookup(
routes: ElegantConstRoute[],
lookup = new Map<string, ContextRouteLookupItem>()
): Map<string, ContextRouteLookupItem> {
routes.forEach(route => {
const routeName = route.name ? String(route.name) : '';
const routePath = route.path ? String(route.path) : '';
const item: ContextRouteLookupItem = {
key: routeName || routePath,
label: getContextMenuLabel(route),
routeKey: routeName || null,
routePath: routePath || null
};
if (routeName) {
lookup.set(routeName, item);
}
if (routePath) {
lookup.set(routePath, item);
}
route.children?.forEach(child => {
createContextRouteLookup([child], lookup);
});
});
return lookup;
}
function enrichContextMenu(
menu: App.ObjectContext.Menu,
routeLookup: Map<string, ContextRouteLookupItem>
): App.ObjectContext.Menu {
const matchedRoute =
routeLookup.get(String(menu.routeKey || '')) ||
routeLookup.get(String(menu.routePath || '')) ||
routeLookup.get(menu.key);
return {
key: matchedRoute?.key || menu.key,
label: menu.label || matchedRoute?.label || menu.key,
routeKey: menu.routeKey || matchedRoute?.routeKey || null,
routePath: menu.routePath || matchedRoute?.routePath || null,
children: menu.children?.map(child => enrichContextMenu(child, routeLookup)) || []
};
}
function getLeafRoutes(routes: ElegantConstRoute[]): ElegantConstRoute[] {
return routes.flatMap(route => {
if (route.children?.length) {
return getLeafRoutes(route.children);
}
return [route];
});
}
export const useObjectContextStore = defineStore(SetupStoreId.ObjectContext, () => {
const routeStore = useRouteStore();
const domainKey = ref<App.ObjectContext.DomainKey>('');
const objectType = ref<App.ObjectContext.ObjectType>('');
const objectId = ref('');
const objectName = ref('');
const objectSummary = ref<App.ObjectContext.Summary | null>(null);
const contextScopedMenus = ref<App.ObjectContext.Menu[]>([]);
const buttonCodes = ref<string[]>([]);
const defaultRouteKey = ref('');
const defaultRoutePath = ref('');
const isReady = ref(false);
const hasContext = computed(() => isReady.value && Boolean(domainKey.value) && Boolean(objectId.value));
function patchState(state: App.ObjectContext.State) {
domainKey.value = state.domainKey;
objectType.value = state.objectType;
objectId.value = state.objectId;
objectName.value = state.objectName;
objectSummary.value = state.objectSummary;
contextScopedMenus.value = state.contextScopedMenus;
buttonCodes.value = state.buttonCodes;
defaultRouteKey.value = state.defaultRouteKey;
defaultRoutePath.value = state.defaultRoutePath;
isReady.value = state.isReady;
}
function clearContext() {
patchState(createEmptyState());
}
function resolveDefaultRoute(
config: App.ObjectContext.DomainConfig,
domainRoutes: ElegantConstRoute[],
context: Api.ObjectContext.ContextInfo
) {
const leafRoutes = getLeafRoutes(domainRoutes);
const defaultRouteByKey = (routeKey?: string | null) => leafRoutes.find(route => route.name === routeKey);
const defaultRouteByPath = (routePath?: string | null) =>
leafRoutes.find(route => normalizePath(route.path) === normalizePath(routePath || ''));
const matchedContextByKey = defaultRouteByKey(context.defaultRouteKey);
if (matchedContextByKey?.name && matchedContextByKey.path) {
return {
defaultRouteKey: String(matchedContextByKey.name),
defaultRoutePath: matchedContextByKey.path
};
}
const matchedContextByPath = defaultRouteByPath(context.defaultRoutePath);
if (matchedContextByPath?.name && matchedContextByPath.path) {
return {
defaultRouteKey: String(matchedContextByPath.name),
defaultRoutePath: matchedContextByPath.path
};
}
const matchedFallbackByKey = defaultRouteByKey(config.fallbackDefaultRouteKey);
if (matchedFallbackByKey?.name && matchedFallbackByKey.path) {
return {
defaultRouteKey: String(matchedFallbackByKey.name),
defaultRoutePath: matchedFallbackByKey.path
};
}
const matchedFallbackByPath = defaultRouteByPath(config.fallbackDefaultRoutePath);
if (matchedFallbackByPath?.name && matchedFallbackByPath.path) {
return {
defaultRouteKey: String(matchedFallbackByPath.name),
defaultRoutePath: matchedFallbackByPath.path
};
}
const [firstLeafRoute] = leafRoutes;
if (firstLeafRoute?.name && firstLeafRoute.path) {
return {
defaultRouteKey: String(firstLeafRoute.name),
defaultRoutePath: firstLeafRoute.path
};
}
return {
defaultRouteKey: context.defaultRouteKey || config.fallbackDefaultRouteKey,
defaultRoutePath: context.defaultRoutePath || config.fallbackDefaultRoutePath
};
}
function applyContext(config: App.ObjectContext.DomainConfig, context: Api.ObjectContext.ContextInfo) {
const domainRootRoute = findDomainRootRoute(routeStore.authRoutes, config);
const domainRoutes: ElegantConstRoute[] =
domainRootRoute?.children?.filter((route: ElegantConstRoute) => !isEntryRoute(route, config)) || [];
const routeLookup = createContextRouteLookup(domainRoutes);
// 对象上下文菜单以接口返回为准,前端只补全跳转所需的本地路由信息。
const contextMenus = context.contextScopedMenus.map(menu => enrichContextMenu(menu, routeLookup));
const resolvedDefaultRoute = resolveDefaultRoute(config, domainRoutes, context);
patchState({
...context,
contextScopedMenus: contextMenus,
defaultRouteKey: resolvedDefaultRoute.defaultRouteKey,
defaultRoutePath: resolvedDefaultRoute.defaultRoutePath,
isReady: true
});
}
function getObjectIdFromRoute(route: Pick<RouteLocationNormalized, 'query'>) {
const routeObjectId = route.query?.[OBJECT_CONTEXT_QUERY_KEY];
if (Array.isArray(routeObjectId)) {
return String(routeObjectId[0] || '');
}
if (routeObjectId === null || routeObjectId === undefined) {
return '';
}
return String(routeObjectId);
}
function getContextQuery(targetObjectId = objectId.value): LocationQueryRaw {
if (!targetObjectId) {
return {};
}
return {
[OBJECT_CONTEXT_QUERY_KEY]: targetObjectId
};
}
function createEntryLocation(config: App.ObjectContext.DomainConfig): RouteLocationRaw {
return {
path: config.entryRoutePath
};
}
function createDefaultLocation(config: App.ObjectContext.DomainConfig, targetObjectId: string): RouteLocationRaw {
const query = getContextQuery(targetObjectId);
if (defaultRouteKey.value) {
return {
name: defaultRouteKey.value,
query
};
}
if (defaultRoutePath.value) {
return {
path: defaultRoutePath.value,
query
};
}
return {
path: config.fallbackDefaultRoutePath,
query
};
}
async function enterContext(config: App.ObjectContext.DomainConfig, targetObjectId: string) {
const result = await fetchGetObjectContext(config, targetObjectId);
if (!result.error && result.data) {
applyContext(config, result.data);
}
return result;
}
async function switchContext(config: App.ObjectContext.DomainConfig, targetObjectId: string) {
return enterContext(config, targetObjectId);
}
async function ensureContextByRoute(to: RouteLocationNormalized): Promise<RouteLocationRaw | null> {
const domainConfig = getObjectContextDomainConfigByPath(to.path);
if (!domainConfig) {
if (hasContext.value) {
clearContext();
}
return null;
}
const routeObjectId = getObjectIdFromRoute(to);
if (!routeObjectId) {
clearContext();
if (isObjectContextEntryPath(to.path, domainConfig)) {
return null;
}
return createEntryLocation(domainConfig);
}
const isSameContext =
hasContext.value && domainKey.value === domainConfig.domainKey && objectId.value === routeObjectId;
if (!isSameContext) {
const { error } = await enterContext(domainConfig, routeObjectId);
if (error) {
clearContext();
return createEntryLocation(domainConfig);
}
}
if (isObjectContextEntryPath(to.path, domainConfig)) {
return createDefaultLocation(domainConfig, routeObjectId);
}
return null;
}
function getMenuRouteLocation(
menu: App.ObjectContext.Menu,
targetObjectId = objectId.value
): RouteLocationRaw | null {
const query = getContextQuery(targetObjectId);
if (menu.routeKey) {
return {
name: menu.routeKey,
query
};
}
if (menu.routePath) {
return {
path: menu.routePath,
query
};
}
return null;
}
return {
domainKey,
objectType,
objectId,
objectName,
objectSummary,
contextScopedMenus,
buttonCodes,
defaultRouteKey,
defaultRoutePath,
isReady,
hasContext,
clearContext,
enterContext,
switchContext,
ensureContextByRoute,
getContextQuery,
getMenuRouteLocation
};
});

View File

@@ -3,13 +3,12 @@ import type { RouteRecordRaw } from 'vue-router';
import { defineStore } from 'pinia';
import { useBoolean } from '@sa/hooks';
import type { CustomRoute, ElegantConstRoute, LastLevelRouteKey, RouteKey, RouteMap } from '@elegant-router/types';
import { router } from '@/router';
import { fetchGetUserRoutes, fetchIsRouteExist } from '@/service/api';
import { SetupStoreId } from '@/enum';
import { createStaticRoutes, getAuthVueRoutes } from '@/router/routes';
import { ROOT_ROUTE } from '@/router/routes/builtin';
import { getRouteName, getRoutePath } from '@/router/elegant/transform';
import { getGlobalRouter } from '@/router/instance';
import { useAuthStore } from '../auth';
import { useDictStore } from '../dict';
import { useTabStore } from '../tab';
import {
filterAuthRoutesByRoles,
@@ -23,8 +22,27 @@ import {
updateLocaleOfGlobalMenus
} from './shared';
type RouteModule = typeof import('@/router/routes');
async function loadRouteModule(): Promise<RouteModule> {
return import('@/router/routes');
}
function createRootRoute(redirect: string): CustomRoute {
return {
name: 'root',
path: '/',
redirect,
meta: {
title: 'root',
constant: true
}
};
}
export const useRouteStore = defineStore(SetupStoreId.Route, () => {
const authStore = useAuthStore();
const dictStore = useDictStore();
const tabStore = useTabStore();
const { bool: isInitConstantRoute, setBool: setIsInitConstantRoute } = useBoolean();
const { bool: isInitAuthRoute, setBool: setIsInitAuthRoute } = useBoolean();
@@ -117,7 +135,7 @@ export const useRouteStore = defineStore(SetupStoreId.Route, () => {
* @param routeKey
*/
async function resetRouteCache(routeKey?: RouteKey) {
const routeName = routeKey || (router.currentRoute.value.name as RouteKey);
const routeName = routeKey || (getGlobalRouter().currentRoute.value.name as RouteKey);
excludeCacheRoutes.value.push(routeName);
@@ -127,7 +145,7 @@ export const useRouteStore = defineStore(SetupStoreId.Route, () => {
}
/** 全局面包屑 */
const breadcrumbs = computed(() => getBreadcrumbsByRoute(router.currentRoute.value, menus.value));
const breadcrumbs = computed(() => getBreadcrumbsByRoute(getGlobalRouter().currentRoute.value, menus.value));
/** 重置 store */
async function resetStore() {
@@ -151,11 +169,12 @@ export const useRouteStore = defineStore(SetupStoreId.Route, () => {
async function initConstantRoute() {
if (isInitConstantRoute.value) return;
const { createStaticRoutes } = await loadRouteModule();
const staticRoute = createStaticRoutes();
addConstantRoutes(staticRoute.constantRoutes);
handleConstantAndAuthRoutes();
await handleConstantAndAuthRoutes();
setIsInitConstantRoute(true);
@@ -169,8 +188,10 @@ export const useRouteStore = defineStore(SetupStoreId.Route, () => {
await authStore.initUserInfo();
}
await dictStore.initDictCache();
if (authRouteMode.value === 'static') {
initStaticAuthRoute();
await initStaticAuthRoute();
} else {
await initDynamicAuthRoute();
}
@@ -179,7 +200,8 @@ export const useRouteStore = defineStore(SetupStoreId.Route, () => {
}
/** 初始化静态权限路由 */
function initStaticAuthRoute() {
async function initStaticAuthRoute() {
const { createStaticRoutes } = await loadRouteModule();
const { authRoutes: staticAuthRoutes } = createStaticRoutes();
if (authStore.isStaticSuper) {
@@ -190,7 +212,7 @@ export const useRouteStore = defineStore(SetupStoreId.Route, () => {
addAuthRoutes(filteredAuthRoutes);
}
handleConstantAndAuthRoutes();
await handleConstantAndAuthRoutes();
setIsInitAuthRoute(true);
}
@@ -204,11 +226,11 @@ export const useRouteStore = defineStore(SetupStoreId.Route, () => {
addAuthRoutes(routes);
handleConstantAndAuthRoutes();
await handleConstantAndAuthRoutes();
setRouteHome(home);
handleUpdateRootRouteRedirect(home);
await handleUpdateRootRouteRedirect(home);
setIsInitAuthRoute(true);
} else {
@@ -218,7 +240,8 @@ export const useRouteStore = defineStore(SetupStoreId.Route, () => {
}
/** 统一处理常量路由和权限路由 */
function handleConstantAndAuthRoutes() {
async function handleConstantAndAuthRoutes() {
const { getAuthVueRoutes } = await loadRouteModule();
const allRoutes = [...constantRoutes.value, ...authRoutes.value];
const sortRoutes = sortRoutesByOrder(allRoutes);
@@ -241,7 +264,7 @@ export const useRouteStore = defineStore(SetupStoreId.Route, () => {
*/
function addRoutesToVueRouter(routes: RouteRecordRaw[]) {
routes.forEach(route => {
const removeFn = router.addRoute(route);
const removeFn = getGlobalRouter().addRoute(route);
addRemoveRouteFn(removeFn);
});
}
@@ -260,11 +283,13 @@ export const useRouteStore = defineStore(SetupStoreId.Route, () => {
*
* @param redirectKey 重定向目标路由 key
*/
function handleUpdateRootRouteRedirect(redirectKey: LastLevelRouteKey) {
async function handleUpdateRootRouteRedirect(redirectKey: LastLevelRouteKey) {
const redirect = getRoutePath(redirectKey);
if (redirect) {
const rootRoute: CustomRoute = { ...ROOT_ROUTE, redirect };
const { getAuthVueRoutes } = await loadRouteModule();
const rootRoute = createRootRoute(redirect);
const router = getGlobalRouter();
router.removeRoute(rootRoute.name);
@@ -287,6 +312,7 @@ export const useRouteStore = defineStore(SetupStoreId.Route, () => {
}
if (authRouteMode.value === 'static') {
const { createStaticRoutes } = await loadRouteModule();
const { authRoutes: staticAuthRoutes } = createStaticRoutes();
return isRouteExistByRouteName(routeName, staticAuthRoutes);
}
@@ -316,6 +342,7 @@ export const useRouteStore = defineStore(SetupStoreId.Route, () => {
return {
resetStore,
routeHome,
authRoutes,
menus,
searchMenus,
updateGlobalMenusByLocale,

View File

@@ -2,10 +2,10 @@ import { computed, ref } from 'vue';
import { useEventListener } from '@vueuse/core';
import { defineStore } from 'pinia';
import type { RouteKey } from '@elegant-router/types';
import { router } from '@/router';
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 {
@@ -35,7 +35,7 @@ export const useTabStore = defineStore(SetupStoreId.Tab, () => {
/** Init home tab */
function initHomeTab() {
homeTab.value = getDefaultHomeTab(router, routeStore.routeHome);
homeTab.value = getDefaultHomeTab(getGlobalRouter(), routeStore.routeHome);
}
/** Get all tabs */
@@ -62,7 +62,7 @@ export const useTabStore = defineStore(SetupStoreId.Tab, () => {
const storageTabs = localStg.get('globalTabs');
if (themeStore.tab.cache && storageTabs) {
const extractedTabs = extractTabsByAllRoutes(router, storageTabs);
const extractedTabs = extractTabsByAllRoutes(getGlobalRouter(), storageTabs);
tabs.value = updateTabsByI18nKey(extractedTabs);
}