/** * 路由工具函数 * * 提供路由相关的工具函数 * * @module utils/router */ import { RouteLocationNormalized, RouteRecordRaw } from 'vue-router' import AppConfig from '@/config' import NProgress from 'nprogress' import 'nprogress/nprogress.css' import i18n, { $t } from '@/locales' import { RoutesAlias } from '@/router/routesAlias' /** 历史遗留登录路径(与 RoutesAlias.Login 等价) */ const LEGACY_LOGIN_PATHS = new Set([RoutesAlias.Login, '/login']) /** 扩展的路由配置类型 */ export type AppRouteRecordRaw = RouteRecordRaw & { hidden?: boolean } /** 顶部进度条配置 */ export const configureNProgress = () => { NProgress.configure({ easing: 'ease', speed: 600, showSpinner: false, parent: 'body' }) } /** * 设置页面标题,根据路由元信息和系统信息拼接标题 * @param to 当前路由对象 */ export const setPageTitle = (to: RouteLocationNormalized): void => { const { title } = to.meta if (title) { setTimeout(() => { document.title = `${formatMenuTitle(String(title))} - ${AppConfig.systemInfo.name}` }, 150) } } /** * 格式化菜单标题 * @param title 菜单标题,可以是 i18n 的 key,也可以是字符串 * @returns 格式化后的菜单标题 */ export const formatMenuTitle = (title: string): string => { if (title) { if (title.startsWith('menus.')) { // 使用 te() 方法检查翻译键值是否存在,避免控制台警告 if (i18n.global.te(title)) { return $t(title) } else { // 如果翻译不存在,返回键值的最后部分作为fallback return title.split('.').pop() || title } } return title } return '' } /** * 解析登录后的安全跳转地址,避免 redirect 指回登录页导致无法进入系统 */ export function resolveSafeRedirectTarget(redirect: unknown, fallback = '/'): string { const raw = typeof redirect === 'string' ? redirect.trim() : '' if (!raw) return fallback const pathOnly = raw.split('?')[0].split('#')[0] const normalized = pathOnly.startsWith('/') ? pathOnly : `/${pathOnly}` if (LEGACY_LOGIN_PATHS.has(normalized)) { return fallback } return raw }