78ff060420
- 模板 art-design-pro(MIT)GitHub 直连克隆后裁剪落地 admin/:删除演示页面/示例数据/mock/未用组件,保留构建与依赖清单 - 品牌化:应用名/标题/侧栏与登录页 logo/浏览器 favicon 全部替换为 all-kefu 自有资源(static/kefu-small.png),中文界面 - 八页骨架:login / force-change-password / dashboard / tenants / conversations / config / stats / settings 占位页 + 6 组路由模块 - 权限菜单:meta.roles 前端过滤,super 全量,tenant 隐藏 租户管理/平台设置(角色值与后端一致) - 开发代理:/api 直转 + /api/public 与 /static 携带租户 Host 改写(VITE_TENANT_PREVIEW_HOST),适配后端 TenantHostMiddleware - 认证 API 为开发桩(角色调试开关),Task 3 对接真实登录 Co-Authored-By: Claude Code <noreply@anthropic.com>
86 lines
2.1 KiB
TypeScript
86 lines
2.1 KiB
TypeScript
/**
|
|
* 路由工具模块
|
|
*
|
|
* 提供路由处理和菜单路径相关的工具函数
|
|
*
|
|
* ## 主要功能
|
|
*
|
|
* - iframe 路由检测,判断是否为外部嵌入页面
|
|
* - 菜单项有效性验证,过滤隐藏和无效菜单
|
|
* - 路径标准化处理,统一路径格式
|
|
* - 递归查找菜单树中第一个有效路径
|
|
* - 支持多级嵌套菜单的路径解析
|
|
*
|
|
* ## 使用场景
|
|
*
|
|
* - 系统初始化时获取默认跳转路径
|
|
* - 菜单权限过滤后获取首个可访问页面
|
|
* - 路由重定向逻辑处理
|
|
* - iframe 页面特殊处理
|
|
*
|
|
* @module utils/navigation/route
|
|
* @author Art Design Pro Team
|
|
*/
|
|
|
|
import { AppRouteRecord } from '@/types'
|
|
|
|
// 检查是否为 iframe 路由
|
|
export function isIframe(url: string): boolean {
|
|
return url.startsWith('/outside/iframe/')
|
|
}
|
|
|
|
/**
|
|
* 判断菜单项是否可作为默认导航落点
|
|
* 隐藏的全屏页面虽然不展示在菜单中,但仍然可能是合法首页。
|
|
*/
|
|
export const isNavigableMenuItem = (menuItem: AppRouteRecord): boolean => {
|
|
if (!menuItem.path || !menuItem.path.trim()) {
|
|
return false
|
|
}
|
|
|
|
if (!menuItem.meta?.isHide) {
|
|
return true
|
|
}
|
|
|
|
return menuItem.meta?.isFullPage === true
|
|
}
|
|
|
|
/**
|
|
* 标准化路径格式
|
|
* @param path 路径
|
|
* @returns 标准化后的路径
|
|
*/
|
|
const normalizePath = (path: string): string => {
|
|
return path.startsWith('/') ? path : `/${path}`
|
|
}
|
|
|
|
/**
|
|
* 递归获取菜单的第一个有效路径
|
|
* @param menuList 菜单列表
|
|
* @returns 第一个有效路径,如果没有找到则返回空字符串
|
|
*/
|
|
export const getFirstMenuPath = (menuList: AppRouteRecord[]): string => {
|
|
if (!Array.isArray(menuList) || menuList.length === 0) {
|
|
return ''
|
|
}
|
|
|
|
for (const menuItem of menuList) {
|
|
if (!isNavigableMenuItem(menuItem)) {
|
|
continue
|
|
}
|
|
|
|
// 如果有子菜单,优先查找子菜单
|
|
if (menuItem.children?.length) {
|
|
const childPath = getFirstMenuPath(menuItem.children)
|
|
if (childPath) {
|
|
return childPath
|
|
}
|
|
}
|
|
|
|
// 返回当前菜单项的标准化路径
|
|
return normalizePath(menuItem.path!)
|
|
}
|
|
|
|
return ''
|
|
}
|