MixTopMenu.vue 4.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181
  1. <template>
  2. <div class="mix-top-menu">
  3. <a-menu
  4. mode="horizontal"
  5. :selectedKeys="selectedKeys"
  6. @select="handleMenuSelect"
  7. class="mix-top-menu-container"
  8. >
  9. <!-- 工作台菜单 -->
  10. <a-menu-item key="workbench" @click="handleWorkbenchClick">
  11. <template #icon>
  12. <BearJiaIcon icon="HomeOutlined" />
  13. </template>
  14. 主看板
  15. </a-menu-item>
  16. <!-- 一级菜单 - 只显示一级,不显示下拉 -->
  17. <a-menu-item
  18. v-for="(router, index) in menuData"
  19. :key="`${router.path}-${index}`"
  20. @click="handleFirstLevelMenuClick(router)"
  21. >
  22. <template #icon>
  23. <BearJiaIcon :icon="router.meta?.icon || 'MenuOutlined'" />
  24. </template>
  25. {{ router.meta?.title }}
  26. </a-menu-item>
  27. </a-menu>
  28. </div>
  29. </template>
  30. <script setup>
  31. import { ref, computed, defineProps, defineEmits, watch, defineExpose } from 'vue';
  32. import { BearJiaIcon } from '@/utils/BearJiaIcon.js';
  33. const props = defineProps({
  34. menuData: {
  35. type: Array,
  36. default: () => []
  37. },
  38. currentFirstLevelMenu: {
  39. type: Object,
  40. default: null
  41. }
  42. });
  43. const emit = defineEmits(['firstLevelMenuSelect', 'menuSelect']);
  44. // 菜单状态
  45. const selectedKeys = ref(['workbench']); // 默认选中工作台
  46. // 监听当前一级菜单变化
  47. watch(() => props.currentFirstLevelMenu, (newValue) => {
  48. if (newValue) {
  49. const menuIndex = props.menuData.findIndex(item => item.path === newValue.path);
  50. if (menuIndex !== -1) {
  51. selectedKeys.value = [`${newValue.path}-${menuIndex}`];
  52. }
  53. } else {
  54. selectedKeys.value = ['workbench'];
  55. }
  56. }, { immediate: true });
  57. // 设置当前激活菜单(用于页面刷新后恢复状态)
  58. const setCurrentMenu = (fullPath) => {
  59. console.log('MixTopMenu.setCurrentMenu 被调用,路径:', fullPath);
  60. if (!props.menuData || props.menuData.length === 0) {
  61. console.log('MixTopMenu 菜单数据为空');
  62. return;
  63. }
  64. // 检查是否是工作台
  65. if (fullPath === '/ufo/home/workbench') {
  66. selectedKeys.value = ['workbench'];
  67. console.log('MixTopMenu 设置工作台激活');
  68. return;
  69. }
  70. // 查找路径所属的一级菜单
  71. for (const [index, router] of props.menuData.entries()) {
  72. if (router.children) {
  73. for (const child of router.children) {
  74. const childFullPath = `${router.path}/${child.path}`;
  75. // 检查二级菜单
  76. if (child.path === fullPath || childFullPath === fullPath) {
  77. selectedKeys.value = [`${router.path}-${index}`];
  78. console.log('MixTopMenu 找到二级菜单,激活一级菜单');
  79. return;
  80. }
  81. // 检查三级菜单
  82. if (child.children && child.children.length > 0) {
  83. for (const threeLevel of child.children) {
  84. const threeFullPath = `${router.path}/${threeLevel.path}`;
  85. if (threeLevel.path === fullPath || threeFullPath === fullPath) {
  86. selectedKeys.value = [`${router.path}-${index}`];
  87. console.log('MixTopMenu 找到三级菜单,激活一级菜单');
  88. return;
  89. }
  90. }
  91. }
  92. }
  93. }
  94. }
  95. console.log('MixTopMenu 未找到匹配的菜单项');
  96. };
  97. defineExpose({ setCurrentMenu });
  98. // 处理菜单选择
  99. const handleMenuSelect = ({ key }) => {
  100. selectedKeys.value = [key];
  101. };
  102. // 处理工作台点击
  103. const handleWorkbenchClick = () => {
  104. selectedKeys.value = ['workbench'];
  105. emit('menuSelect', {
  106. fatherName: 'HomePage',
  107. fatherPath: '/ufo/home',
  108. fatherTitle: '主页',
  109. name: 'Workbench',
  110. path: 'workbench',
  111. title: '主看板',
  112. component: null
  113. });
  114. // 清空一级菜单选择
  115. emit('firstLevelMenuSelect', null);
  116. };
  117. // 处理一级菜单点击
  118. const handleFirstLevelMenuClick = (router) => {
  119. try {
  120. console.log('混合模式一级菜单点击:', router);
  121. const menuIndex = props.menuData.findIndex(item => item.path === router.path);
  122. selectedKeys.value = [`${router.path}-${menuIndex}`];
  123. // 通知父组件一级菜单选择变化
  124. emit('firstLevelMenuSelect', router);
  125. } catch (error) {
  126. console.error('一级菜单点击错误:', error);
  127. }
  128. };
  129. </script>
  130. <style scoped>
  131. .mix-top-menu {
  132. flex: 1;
  133. display: flex;
  134. justify-content: center;
  135. }
  136. .mix-top-menu-container {
  137. border-bottom: none;
  138. background: transparent;
  139. line-height: 56px;
  140. height: 56px;
  141. }
  142. .mix-top-menu-container .ant-menu-item {
  143. border-bottom: none;
  144. height: 56px;
  145. line-height: 56px;
  146. }
  147. .mix-top-menu-container .ant-menu-item:hover {
  148. color: var(--primary-color);
  149. }
  150. .mix-top-menu-container .ant-menu-item-selected {
  151. color: var(--primary-color);
  152. border-bottom: 2px solid var(--primary-color);
  153. }
  154. </style>