LayoutMenu.tsx 6.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221
  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. isTop: {
  44. type: Boolean as PropType<boolean>,
  45. default: false,
  46. },
  47. menuMode: {
  48. type: [String] as PropType<MenuModeEnum | null>,
  49. default: '',
  50. },
  51. },
  52. setup(props) {
  53. const menusRef = ref<Menu[]>([]);
  54. const flatMenusRef = ref<Menu[]>([]);
  55. const { currentRoute, push } = useRouter();
  56. // const { addTab } = useTabs();
  57. const getProjectConfigRef = computed(() => {
  58. return appStore.getProjectConfig;
  59. });
  60. const getIsHorizontalRef = computed(() => {
  61. return unref(getProjectConfigRef).menuSetting.mode === MenuModeEnum.HORIZONTAL;
  62. });
  63. onMounted(() => {
  64. genMenus();
  65. });
  66. const [throttleHandleSplitLeftMenu] = useThrottle(handleSplitLeftMenu, 50);
  67. // watch(
  68. // () => menuStore.getCurrentTopSplitMenuPathState,
  69. // async (parentPath: string) => {
  70. // throttleHandleSplitLeftMenu(parentPath);
  71. // }
  72. // );
  73. watch(
  74. [() => unref(currentRoute).path, () => props.splitType],
  75. async ([path, splitType]: [string, MenuSplitTyeEnum]) => {
  76. if (splitType !== MenuSplitTyeEnum.LEFT && !unref(getIsHorizontalRef)) return;
  77. const parentPath = await getCurrentParentPath(path);
  78. parentPath && throttleHandleSplitLeftMenu(parentPath);
  79. },
  80. {
  81. immediate: true,
  82. }
  83. );
  84. watch(
  85. [() => permissionStore.getLastBuildMenuTimeState, permissionStore.getBackMenuListState],
  86. () => {
  87. genMenus();
  88. }
  89. );
  90. watch([() => appStore.getProjectConfig.menuSetting.split], () => {
  91. if (props.splitType !== MenuSplitTyeEnum.LEFT && !unref(getIsHorizontalRef)) return;
  92. genMenus();
  93. });
  94. async function handleSplitLeftMenu(parentPath: string) {
  95. const isSplitMenu = unref(getProjectConfigRef).menuSetting.split;
  96. if (!isSplitMenu) return;
  97. const { splitType } = props;
  98. // 菜单分割模式-left
  99. if (splitType === MenuSplitTyeEnum.LEFT) {
  100. const children = await getChildrenMenus(parentPath);
  101. if (!children) return;
  102. const flatChildren = await getFlatChildrenMenus(children);
  103. flatMenusRef.value = flatChildren;
  104. menusRef.value = children;
  105. }
  106. }
  107. async function genMenus() {
  108. const isSplitMenu = unref(getProjectConfigRef).menuSetting.split;
  109. // 普通模式
  110. const { splitType } = props;
  111. if (splitType === MenuSplitTyeEnum.NONE || !isSplitMenu) {
  112. flatMenusRef.value = await getFlatMenus();
  113. menusRef.value = await getMenus();
  114. return;
  115. }
  116. // 菜单分割模式-top
  117. if (splitType === MenuSplitTyeEnum.TOP) {
  118. const parentPath = await getCurrentParentPath(unref(currentRoute).path);
  119. menuStore.commitCurrentTopSplitMenuPathState(parentPath);
  120. const shallowMenus = await getShallowMenus();
  121. flatMenusRef.value = shallowMenus;
  122. menusRef.value = shallowMenus;
  123. return;
  124. }
  125. }
  126. function handleMenuClick(menu: Menu) {
  127. const { path } = menu;
  128. if (path) {
  129. const { splitType } = props;
  130. // 菜单分割模式-top
  131. if (splitType === MenuSplitTyeEnum.TOP) {
  132. menuStore.commitCurrentTopSplitMenuPathState(path);
  133. }
  134. push(path);
  135. // addTab(path as PageEnum, true);
  136. }
  137. }
  138. async function beforeMenuClickFn(menu: Menu) {
  139. const { meta: { externalLink } = {} } = menu;
  140. if (externalLink) {
  141. window.open(externalLink, '_blank');
  142. return false;
  143. }
  144. return true;
  145. }
  146. function handleClickSearchInput() {
  147. if (menuStore.getCollapsedState) {
  148. menuStore.commitCollapsedState(false);
  149. }
  150. }
  151. const showSearchRef = computed(() => {
  152. const { showSearch, type, mode } = unref(getProjectConfigRef).menuSetting;
  153. return (
  154. showSearch &&
  155. props.showSearch &&
  156. !(type === MenuTypeEnum.MIX && mode === MenuModeEnum.HORIZONTAL)
  157. );
  158. });
  159. return () => {
  160. const {
  161. showLogo,
  162. menuSetting: { type: menuType, mode, theme, collapsed, collapsedShowTitle },
  163. } = unref(getProjectConfigRef);
  164. const isSidebarType = menuType === MenuTypeEnum.SIDEBAR;
  165. const isShowLogo = showLogo && isSidebarType;
  166. const themeData = props.theme || theme;
  167. return (
  168. <BasicMenu
  169. beforeClickFn={beforeMenuClickFn}
  170. onMenuClick={handleMenuClick}
  171. type={menuType}
  172. mode={props.menuMode || mode}
  173. class="layout-menu"
  174. collapsedShowTitle={collapsedShowTitle}
  175. theme={themeData}
  176. showLogo={isShowLogo}
  177. search={unref(showSearchRef) && !collapsed}
  178. items={unref(menusRef)}
  179. flatItems={unref(flatMenusRef)}
  180. onClickSearchInput={handleClickSearchInput}
  181. appendClass={props.splitType === MenuSplitTyeEnum.TOP}
  182. isTop={props.isTop}
  183. >
  184. {{
  185. header: () =>
  186. isShowLogo && (
  187. <Logo
  188. showTitle={!collapsed}
  189. class={[`layout-menu__logo`, collapsed ? 'justify-center' : '', themeData]}
  190. />
  191. ),
  192. }}
  193. </BasicMenu>
  194. );
  195. };
  196. },
  197. });