index.vue 3.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206
  1. <template>
  2. <a-menu v-model:selected-keys="selectedKey"
  3. :default-open-keys="selectedKey">
  4. <template v-for="menu in menuData" :key="menu.key">
  5. <a-sub-menu v-if="menu.children" :key="menu.key">
  6. <template #icon>
  7. <component :is="menu.icon"></component>
  8. </template>
  9. <template #title>{{ menu.label }}</template>
  10. <a-menu-item v-for="child in menu.children" :key="child.key" :disabled="child.disabled"
  11. @click="$router.push(child.key)">
  12. {{ child.label }}
  13. </a-menu-item>
  14. </a-sub-menu>
  15. <a-menu-item v-else :key="menu.key" :disabled="menu.disabled" @click="$router.push(menu.key)">
  16. <template #icon>
  17. <component :is="menu.icon"></component>
  18. </template>
  19. {{ menu.label }}
  20. </a-menu-item>
  21. </template>
  22. </a-menu>
  23. </template>
  24. <script setup>
  25. import { onMounted, ref, watch } from 'vue'
  26. import { routes } from '@/router'
  27. import { useUserStore } from '@/store/modules/user'
  28. import { useRouteListener } from '@/utils/route-listener'
  29. import { isElectron } from '../../utils/electron'
  30. import { canShowInMenu } from '@/utils/permission'
  31. const userStore = useUserStore()
  32. const user = ref({})
  33. const electron = ref(false)
  34. const menuData = ref([])
  35. const { selectedKey } = useRouteListener()
  36. const checkEnv = (route) => {
  37. if (!route.meta) return true
  38. if (route.meta.onlyWeb) return !electron.value
  39. if (route.meta.onlyElectron) return !!electron.value
  40. return true
  41. }
  42. const joinRoutePath = (parentPath, routePath) => {
  43. const base = parentPath.endsWith('/') ? parentPath.slice(0, -1) : parentPath
  44. const segment = routePath.startsWith('/') ? routePath : `/${routePath}`
  45. return `${base}${segment}`.replace(/\/+/g, '/')
  46. }
  47. const generateMenu = (routeList, parentPath = '') => {
  48. return routeList
  49. .filter((route) => canShowInMenu(route, user.value) && checkEnv(route))
  50. .map((route) => {
  51. const fullPath = joinRoutePath(parentPath, route.path)
  52. const menu = {
  53. key: fullPath,
  54. label: route.meta?.title || route.name,
  55. icon: route.meta?.icon || '',
  56. disabled: route.meta?.disabled || false
  57. }
  58. if (route.children && route.children.length > 0) {
  59. const childPrefix = fullPath.endsWith('/') ? fullPath : `${fullPath}/`
  60. menu.children = generateMenu(route.children, childPrefix)
  61. if (menu.children.length === 0) return null
  62. if (route.meta?.flatMenu && menu.children.length === 1) {
  63. const only = menu.children[0]
  64. return {
  65. ...only,
  66. icon: menu.icon || only.icon,
  67. label: menu.label || only.label
  68. }
  69. }
  70. }
  71. return menu
  72. })
  73. .filter(Boolean)
  74. }
  75. const refreshMenu = async () => {
  76. user.value = await userStore.getInfo()
  77. if ((!user.value.permissionCodes || user.value.permissionCodes.length === 0) && userStore.refreshPermissions) {
  78. await userStore.refreshPermissions()
  79. user.value = userStore.$state
  80. }
  81. electron.value = isElectron()
  82. menuData.value = generateMenu(routes)
  83. }
  84. onMounted(refreshMenu)
  85. watch(
  86. () => [userStore.uuid, userStore.session],
  87. () => {
  88. refreshMenu()
  89. }
  90. )
  91. </script>