front/src/utils/menu-icon.ts
zzh cf4d2c4a3f feat: 新增 9610 申报页与批量清单/报关单操作
同步 SPA 回退、权限目录、拣货绑定组件及相关系统页调整。

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-08-30 17:46:04 +08:00

184 lines
6.3 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import * as Icons from '@arco-design/web-vue/es/icon'
import type { Component } from 'vue'
/** 一级菜单默认图标(按 locale key) */
export const TOP_MENU_DEFAULT_ICONS: Record<string, string> = {
'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<string, string> = {
'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.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<string, Component>)[pascal] ?? null
}
/** 同名菜单(如「新手指引」)按 path 区分 locale */
export const PATH_TO_LOCALE_KEY: Record<string, string> = {
'/track/guide': 'menu.track.trackGuide',
'/order/guide': 'menu.order.orderGuide',
'/channel/guide': 'menu.channel.channelGuide',
}
type MenuIconItem = {
name?: string
path?: string
route?: string
meta?: {
icon?: string
title?: string
}
}
function resolveLocaleKey(
menuItem: MenuIconItem,
nameToLocaleKeyMap?: Record<string, string>,
): 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<string, string>,
): 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<string, string>,
): 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
}