import { RoutesAlias } from '../routesAlias.js' import { resolveBackendMenuTitle } from '../../utils/backend-menu-title.js' const PHASE_1_COMPONENTS = { console: '/dashboard/console', user: '/system/user', role: '/system/role', menu: '/system/menu', userLogin: '/system/user-login' } const LEGACY_BACKEND_ICON_MAP = Object.freeze({ SmartToy: 'ri:robot-2-line', Psychology: 'ri:lightbulb-flash-line', History: 'ri:history-line', Cable: 'ri:plug-2-line', StorageSharp: 'ri:server-line', Warehouse: 'ri:store-2-line', Inventory2Outlined: 'ri:archive-line', DeckOutlined: 'ri:layout-grid-line', FormatListNumberedOutlined: 'ri:file-list-3-line', Beenhere: 'ri:checkbox-circle-line', ManageHistoryOutlined: 'ri:history-line', AssessmentOutlined: 'ri:bar-chart-box-line', QueryStats: 'ri:line-chart-line', ScreenSearchDesktop: 'ri:computer-line', Dvr: 'ri:file-list-3-line', Token: 'ri:key-2-line', GroupAddOutlined: 'ri:user-add-line', People: 'ri:group-line', Style: 'ri:price-tag-line', Groups: 'ri:group-line', SettingsOutlined: 'ri:settings-line', MenuOpen: 'ri:menu-unfold-3-line', Straighten: 'ri:table-line', MenuBook: 'ri:book-2-line', ConfirmationNumber: 'ri:price-tag-line', Engineering: 'ri:tools-line', TripOrigin: 'ri:checkbox-blank-circle-line' }) function adaptBackendMenuTree(menuTree) { if (!Array.isArray(menuTree)) { return [] } return menuTree .map((item) => adaptMenuNode(item, { depth: 0, parentRoutePath: '' })) .filter(Boolean) } function adaptMenuNode(node, context) { if (!node || typeof node !== 'object') { return null } if (node.type !== void 0 && node.type !== 0) { return null } const { depth, parentRoutePath } = context const rawRoute = typeof node.route === 'string' ? node.route.trim() : '' const fullRoutePath = buildFullRoutePath(rawRoute, parentRoutePath) const children = Array.isArray(node.children) ? node.children .map((item) => adaptMenuNode(item, { depth: depth + 1, parentRoutePath: fullRoutePath || parentRoutePath }) ) .filter(Boolean) : [] const hasChildren = children.length > 0 const component = resolveComponent(node.component, fullRoutePath, hasChildren) const isFirstLevel = depth === 0 if (!hasChildren && !component) { return null } const path = resolvePath(node, { component, isFirstLevel, hasChildren, rawRoute }) const meta = buildMeta(node) const adapted = { id: normalizeId(node.id), name: buildRouteName(node, path), path, meta } if (hasChildren) { adapted.children = children } if (component) { adapted.component = component } else if (isFirstLevel) { adapted.component = RoutesAlias.Layout } return adapted } function resolveComponent(componentKey, fullRoutePath, hasChildren) { const normalizedKey = typeof componentKey === 'string' ? componentKey.trim() : '' if (!normalizedKey && hasChildren) { return '' } if (!normalizedKey) { return normalizeComponentPath(fullRoutePath) } return PHASE_1_COMPONENTS[normalizedKey] || normalizeComponentPath(fullRoutePath) } function resolvePath(node, { component, isFirstLevel, hasChildren, rawRoute }) { if (rawRoute) { if (!isFirstLevel && rawRoute.startsWith('/')) { return normalizeComponentPath(rawRoute) } return sanitizePath(rawRoute) } if (component) { const componentPath = component.replace(/^\//, '') return isFirstLevel ? `/${componentPath}` : componentPath.split('/').pop() || '' } const rawPath = typeof node.path === 'string' ? node.path.trim() : '' if (rawPath) { return sanitizePath(rawPath) } return '' } function buildMeta(node) { const meta = { title: normalizeTitle(node.name || node.meta?.title || '') } const metaSource = node.meta && typeof node.meta === 'object' ? node.meta : node const supportedKeys = [ 'icon', 'keepAlive', 'isHide', 'isHideTab', 'fixedTab', 'link', 'isIframe', 'authList', 'roles' ] supportedKeys.forEach((key) => { if (metaSource[key] !== void 0) { meta[key] = key === 'icon' ? normalizeIcon(metaSource[key]) : metaSource[key] } }) return meta } function normalizeTitle(title) { if (typeof title !== 'string') { return '' } return resolveBackendMenuTitle(title) } function normalizeIcon(icon) { if (typeof icon !== 'string') { return icon } const normalizedIcon = icon.trim() if (!normalizedIcon) { return '' } if (normalizedIcon.includes(':')) { return normalizedIcon } return LEGACY_BACKEND_ICON_MAP[normalizedIcon] || normalizedIcon } function buildRouteName(node, path) { if (typeof node.name === 'string' && node.name.trim()) { return node.name.trim() } if (typeof node.component === 'string' && node.component.trim()) { return node.component.trim() } if (path) { return path .split('/') .filter(Boolean) .map((segment) => segment.charAt(0).toUpperCase() + segment.slice(1)) .join('') } return `Menu${normalizeId(node.id)}` } function normalizeId(id) { if (id === null || id === void 0 || id === '') { return '' } return String(id) } function sanitizePath(path) { return path.replace(/^\/+/, '').replace(/\/+$/, '') } function normalizeComponentPath(fullRoutePath) { if (!fullRoutePath) { return '' } return `/${sanitizePath(fullRoutePath)}` } function buildFullRoutePath(rawRoute, parentRoutePath) { if (!rawRoute) { return normalizeComponentPath(parentRoutePath) } if (rawRoute.startsWith('/')) { return normalizeComponentPath(rawRoute) } const normalizedParent = sanitizePath(parentRoutePath || '') const normalizedRoute = sanitizePath(rawRoute) if (!normalizedRoute) { return normalizeComponentPath(normalizedParent) } if (!normalizedParent) { return `/${normalizedRoute}` } return `/${normalizedParent}/${normalizedRoute}` } export { LEGACY_BACKEND_ICON_MAP, PHASE_1_COMPONENTS, adaptBackendMenuTree, normalizeIcon }