import * as Icons from '@arco-design/web-vue/es/icon' import type { Component } from 'vue' /** 一级菜单默认图标(按 locale key) */ export const TOP_MENU_DEFAULT_ICONS: Record = { 'menu.home': 'IconDashboard', 'menu.user': 'IconUser', 'menu.finance': 'IconStorage', 'menu.order': 'IconFile', 'menu.channel': 'IconLink', 'menu.track': 'IconComputer', 'menu.operation': 'IconSettings', 'menu.api': 'IconComputer', 'menu.system': 'IconSettings', 'menu.xhs': 'IconBook', } /** 子菜单默认图标(按 locale key) */ export const SUB_MENU_DEFAULT_ICONS: Record = { 'menu.home': 'IconHome', 'menu.user.customer': 'IconUserGroup', 'menu.user.profile': 'IconUser', 'menu.user.recharge': 'IconGift', 'menu.finance.rechargeRecord': 'IconList', 'menu.finance.accountFlow': 'IconSwap', 'menu.finance.receivablePayable': 'IconFile', 'menu.order.orderGuide': 'IconBook', 'menu.order.priceCheck': 'IconSearch', 'menu.order.placeOrder': 'IconPlus', 'menu.order.myOrders': 'IconOrderedList', 'menu.order.waybillManage': 'IconStorage', 'menu.order.customs9610Order': 'IconFile', 'menu.order.batchJobs': 'IconSchedule', 'menu.channel.channelGuide': 'IconBook', 'menu.channel.salesProducts': 'IconTag', 'menu.channel.serviceChannels': 'IconSend', 'menu.channel.priceArea': 'IconLocation', 'menu.channel.blacklist': 'IconCloseCircle', 'menu.channel.remoteZones': 'IconCompass', 'menu.channel.weightRules': 'IconExperiment', 'menu.channel.weightRounding': 'IconCode', 'menu.channel.autoTrigger': 'IconThunderbolt', 'menu.channel.issueTemplate': 'IconFile', 'menu.track.trackGuide': 'IconBook', 'menu.track.trackOrder': 'IconList', 'menu.track.warningOrder': 'IconExclamationCircle', 'menu.track.trackState': 'IconCheckCircle', 'menu.track.trackFlag': 'IconFlag', 'menu.track.trackContent': 'IconMessage', 'menu.track.trackPull': 'IconDownload', 'menu.track.trackPush': 'IconUpload', 'menu.track.kpiEarlyWarningConfig': 'IconSettings', 'menu.operation.inboundScan': 'IconImport', 'menu.operation.outboundScan': 'IconExport', 'menu.operation.printLabel': 'IconPrinter', 'menu.operation.parcelArrival': 'IconImport', 'menu.warehouse.parcel': 'IconGift', 'menu.warehouse.inventory': 'IconStorage', 'menu.warehouse.sku': 'IconTags', 'menu.warehouse.inboundNotice': 'IconFile', 'menu.warehouse.binLocation': 'IconLocation', 'menu.api.upstreamInterface': 'IconCloud', 'menu.api.downstreamInterface': 'IconCloudDownload', 'menu.api.createInterface': 'IconPlus', 'menu.api.editInterface': 'IconEdit', 'menu.api.appList': 'IconApps', 'menu.api.requestLog': 'IconFile', 'menu.api.callStatistics': 'IconBarChart', 'menu.api.createApplication': 'IconPlusCircle', 'menu.api.apiDebugger': 'IconBug', 'menu.api.apiLike': 'IconCode', 'menu.api.apiTest': 'IconExperiment', 'menu.system.organization': 'IconUserGroup', 'menu.system.user': 'IconUser', 'menu.system.position': 'IconIdcard', 'menu.system.role': 'IconSafe', 'menu.system.module': 'IconApps', 'menu.system.menu': 'IconMenu', 'menu.system.warehouseAddress': 'IconHome', 'menu.system.country': 'IconPublic', 'menu.system.otherConfig': 'IconSettings', 'menu.system.aiAssistant': 'IconRobot', 'menu.system.aiSkills': 'IconBook', 'menu.system.mcpTools': 'IconApps', 'menu.system.dataPerm': 'IconLock', 'menu.system.dataPermUsers': 'IconUser', 'menu.system.dataPermTemplates': 'IconFile', 'menu.system.dataPermAudit': 'IconHistory', 'menu.xhs.startService': 'IconPlayArrow', 'menu.xhs.analysis': 'IconBarChart', 'menu.xhs.creation': 'IconEdit', 'menu.xhs.publishHistory': 'IconHistory', 'menu.xhs.skills': 'IconApps', 'menu.xhs.humanSettings': 'IconSettings', } export function toPascalIconName(icon: string): string { const trimmed = icon.trim() if (!trimmed) return '' if (/^Icon[A-Z]/.test(trimmed)) return trimmed if (trimmed.startsWith('icon-')) { return `Icon${trimmed .slice(5) .split('-') .map((part) => part.charAt(0).toUpperCase() + part.slice(1)) .join('')}` } return trimmed } export function resolveArcoIcon(icon?: string | null): Component | null { if (!icon) return null const pascal = toPascalIconName(icon) return (Icons as Record)[pascal] ?? null } /** 同名菜单(如「新手指引」)按 path 区分 locale */ export const PATH_TO_LOCALE_KEY: Record = { '/track/guide': 'menu.track.trackGuide', '/order/guide': 'menu.order.orderGuide', '/channel/guide': 'menu.channel.channelGuide', '/marketing/guide': 'menu.marketing.marketingGuide', } type MenuIconItem = { name?: string path?: string route?: string meta?: { icon?: string title?: string } } function resolveLocaleKey( menuItem: MenuIconItem, nameToLocaleKeyMap?: Record, ): string | undefined { const routePath = (menuItem.path || menuItem.route || '').trim() if (routePath && PATH_TO_LOCALE_KEY[routePath]) { return PATH_TO_LOCALE_KEY[routePath] } const title = menuItem.name || menuItem.meta?.title || '' if (!title) return undefined if (title.startsWith('menu.')) return title return nameToLocaleKeyMap?.[title] } /** 解析顶部导航子菜单图标:优先菜单配置,其次默认映射,再继承父级,最后兜底 */ export function getSubMenuIcon( menuItem: MenuIconItem, parentMenuItem?: MenuIconItem, nameToLocaleKeyMap?: Record, ): Component { const configured = resolveArcoIcon(menuItem.meta?.icon) if (configured) return configured const localeKey = resolveLocaleKey(menuItem, nameToLocaleKeyMap) if (localeKey) { const mapped = resolveArcoIcon(SUB_MENU_DEFAULT_ICONS[localeKey]) if (mapped) return mapped } const parentIcon = resolveArcoIcon(parentMenuItem?.meta?.icon) if (parentIcon) return parentIcon return Icons.IconApps } /** 解析顶部导航一级菜单图标:优先菜单配置,其次默认映射,最后兜底 */ export function getTopMenuIcon( menuItem: MenuIconItem, nameToLocaleKeyMap?: Record, ): Component { const configured = resolveArcoIcon(menuItem.meta?.icon) if (configured) return configured const localeKey = resolveLocaleKey(menuItem, nameToLocaleKeyMap) if (localeKey) { const mapped = resolveArcoIcon(TOP_MENU_DEFAULT_ICONS[localeKey]) if (mapped) return mapped } return Icons.IconMenu }