LayoutMenu.tsx 6.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216
  1. import type { PropType } from 'vue';
  2. import type { Menu } from '/@/router/types';
  3. import { computed, defineComponent, unref, ref, onMounted, watch } from 'vue';
  4. import { BasicMenu } from '/@/components/Menu/index';
  5. import Logo from '/@/layouts/Logo.vue';
  6. import { MenuModeEnum, MenuSplitTyeEnum, MenuTypeEnum } from '/@/enums/menuEnum';
  7. // store
  8. import { appStore } from '/@/store/modules/app';
  9. import { menuStore } from '/@/store/modules/menu';
  10. import {
  11. getMenus,
  12. getFlatMenus,
  13. getShallowMenus,
  14. getChildrenMenus,
  15. getFlatChildrenMenus,
  16. getCurrentParentPath,
  17. } from '/@/router/menus/index';
  18. import { useRouter } from 'vue-router';
  19. import { useThrottle } from '/@/hooks/core/useThrottle';
  20. import { permissionStore } from '/@/store/modules/permission';
  21. // import { useTabs } from '/@/hooks/web/useTabs';
  22. // import { PageEnum } from '/@/enums/pageEnum';
  23. // import
  24. export default defineComponent({
  25. name: 'DefaultLayoutMenu',
  26. props: {
  27. theme: {
  28. type: String as PropType<string>,
  29. default: '',
  30. },
  31. splitType: {
  32. type: Number as PropType<MenuSplitTyeEnum>,
  33. default: MenuSplitTyeEnum.NONE,
  34. },
  35. parentMenuPath: {
  36. type: String as PropType<string>,
  37. default: '',
  38. },
  39. showSearch: {
  40. type: Boolean as PropType<boolean>,
  41. default: true,
  42. },
  43. menuMode: {
  44. type: [String] as PropType<MenuModeEnum | null>,
  45. default: '',
  46. },
  47. },
  48. setup(props) {
  49. const menusRef = ref<Menu[]>([]);
  50. const flatMenusRef = ref<Menu[]>([]);
  51. const { currentRoute, push } = useRouter();
  52. // const { addTab } = useTabs();
  53. const getProjectConfigRef = computed(() => {
  54. return appStore.getProjectConfig;
  55. });
  56. const getIsHorizontalRef = computed(() => {
  57. return unref(getProjectConfigRef).menuSetting.mode === MenuModeEnum.HORIZONTAL;
  58. });
  59. onMounted(() => {
  60. genMenus();
  61. });
  62. const [throttleHandleSplitLeftMenu] = useThrottle(handleSplitLeftMenu, 50);
  63. // watch(
  64. // () => menuStore.getCurrentTopSplitMenuPathState,
  65. // async (parentPath: string) => {
  66. // throttleHandleSplitLeftMenu(parentPath);
  67. // }
  68. // );
  69. watch(
  70. [() => unref(currentRoute).path, () => props.splitType],
  71. async ([path, splitType]: [string, MenuSplitTyeEnum]) => {
  72. if (splitType !== MenuSplitTyeEnum.LEFT && !unref(getIsHorizontalRef)) return;
  73. const parentPath = await getCurrentParentPath(path);
  74. parentPath && throttleHandleSplitLeftMenu(parentPath);
  75. },
  76. {
  77. immediate: true,
  78. }
  79. );
  80. watch(
  81. [() => permissionStore.getLastBuildMenuTimeState, permissionStore.getBackMenuListState],
  82. () => {
  83. genMenus();
  84. }
  85. );
  86. watch([() => appStore.getProjectConfig.menuSetting.split], () => {
  87. if (props.splitType !== MenuSplitTyeEnum.LEFT && !unref(getIsHorizontalRef)) return;
  88. genMenus();
  89. });
  90. async function handleSplitLeftMenu(parentPath: string) {
  91. const isSplitMenu = unref(getProjectConfigRef).menuSetting.split;
  92. if (!isSplitMenu) return;
  93. const { splitType } = props;
  94. // 菜单分割模式-left
  95. if (splitType === MenuSplitTyeEnum.LEFT) {
  96. const children = await getChildrenMenus(parentPath);
  97. if (!children) return;
  98. const flatChildren = await getFlatChildrenMenus(children);
  99. flatMenusRef.value = flatChildren;
  100. menusRef.value = children;
  101. }
  102. }
  103. async function genMenus() {
  104. const isSplitMenu = unref(getProjectConfigRef).menuSetting.split;
  105. // 普通模式
  106. const { splitType } = props;
  107. if (splitType === MenuSplitTyeEnum.NONE || !isSplitMenu) {
  108. flatMenusRef.value = await getFlatMenus();
  109. menusRef.value = await getMenus();
  110. return;
  111. }
  112. // 菜单分割模式-top
  113. if (splitType === MenuSplitTyeEnum.TOP) {
  114. const parentPath = await getCurrentParentPath(unref(currentRoute).path);
  115. menuStore.commitCurrentTopSplitMenuPathState(parentPath);
  116. const shallowMenus = await getShallowMenus();
  117. flatMenusRef.value = shallowMenus;
  118. menusRef.value = shallowMenus;
  119. return;
  120. }
  121. }
  122. function handleMenuClick(menu: Menu) {
  123. const { path } = menu;
  124. if (path) {
  125. const { splitType } = props;
  126. // 菜单分割模式-top
  127. if (splitType === MenuSplitTyeEnum.TOP) {
  128. menuStore.commitCurrentTopSplitMenuPathState(path);
  129. }
  130. push(path);
  131. // addTab(path as PageEnum, true);
  132. }
  133. }
  134. async function beforeMenuClickFn(menu: Menu) {
  135. const { meta: { externalLink } = {} } = menu;
  136. if (externalLink) {
  137. window.open(externalLink, '_blank');
  138. return false;
  139. }
  140. return true;
  141. }
  142. function handleClickSearchInput() {
  143. if (menuStore.getCollapsedState) {
  144. menuStore.commitCollapsedState(false);
  145. }
  146. }
  147. const showSearchRef = computed(() => {
  148. const { showSearch, type, mode } = unref(getProjectConfigRef).menuSetting;
  149. return (
  150. showSearch &&
  151. props.showSearch &&
  152. !(type === MenuTypeEnum.MIX && mode === MenuModeEnum.HORIZONTAL)
  153. );
  154. });
  155. return () => {
  156. const {
  157. showLogo,
  158. menuSetting: { type: menuType, mode, theme, collapsed, collapsedShowTitle },
  159. } = unref(getProjectConfigRef);
  160. const isSidebarType = menuType === MenuTypeEnum.SIDEBAR;
  161. const isShowLogo = showLogo && isSidebarType;
  162. const themeData = props.theme || theme;
  163. return (
  164. <BasicMenu
  165. beforeClickFn={beforeMenuClickFn}
  166. onMenuClick={handleMenuClick}
  167. type={menuType}
  168. mode={props.menuMode || mode}
  169. class="layout-menu"
  170. collapsedShowTitle={collapsedShowTitle}
  171. theme={themeData}
  172. showLogo={isShowLogo}
  173. search={unref(showSearchRef) && !collapsed}
  174. items={unref(menusRef)}
  175. flatItems={unref(flatMenusRef)}
  176. onClickSearchInput={handleClickSearchInput}
  177. appendClass={props.splitType === MenuSplitTyeEnum.TOP}
  178. >
  179. {{
  180. header: () =>
  181. isShowLogo && (
  182. <Logo
  183. showTitle={!collapsed}
  184. class={[`layout-menu__logo`, collapsed ? 'justify-center' : '', themeData]}
  185. />
  186. ),
  187. }}
  188. </BasicMenu>
  189. );
  190. };
  191. },
  192. });