AppMenuTree.vue 1.77 KB
<template>
  <template v-for="menu in menus" :key="menu.code">
    <a-sub-menu v-if="menu.children?.length" :key="menu.code">
      <template #icon>
        <component :is="resolveIcon(menu.icon, menu.code)" v-if="resolveIcon(menu.icon, menu.code)" />
      </template>
      <template #title>{{ menu.name }}</template>
      <AppMenuTree :menus="menu.children" />
    </a-sub-menu>
    <a-menu-item v-else :key="menu.path || menu.code">
      <template #icon>
        <component :is="resolveIcon(menu.icon, menu.code)" v-if="resolveIcon(menu.icon, menu.code)" />
      </template>
      {{ menu.name }}
    </a-menu-item>
  </template>
</template>

<script setup lang="ts">
import type { Component } from 'vue'
import type { MenuNode } from '@/types/auth'
import {
  ApiOutlined,
  ApartmentOutlined,
  ControlOutlined,
  GlobalOutlined,
  HomeOutlined,
  MessageOutlined,
  SettingOutlined,
  ShopOutlined,
  StarOutlined,
  TeamOutlined,
  TrophyOutlined,
  UnorderedListOutlined,
  UserOutlined,
} from '@ant-design/icons-vue'

withDefaults(defineProps<{ menus: MenuNode[] }>(), {
  menus: () => [],
})

const iconMap: Record<string, Component> = {
  HomeOutlined,
  GlobalOutlined,
  ApartmentOutlined,
  ShopOutlined,
  UserOutlined,
  StarOutlined,
  UnorderedListOutlined,
  ControlOutlined,
  ApiOutlined,
  TeamOutlined,
  TrophyOutlined,
  SettingOutlined,
  MessageOutlined,
}

const codeIconMap: Record<string, Component> = {
  'substation.user': TeamOutlined,
  'rider.level': TrophyOutlined,
  'system.sub_root': SettingOutlined,
  'system.sub_role': TeamOutlined,
  'system.sub_role_menu': SettingOutlined,
}

function resolveIcon(icon?: string, code?: string) {
  if (icon && iconMap[icon]) return iconMap[icon]
  if (code && codeIconMap[code]) return codeIconMap[code]
  return null
}
</script>