vben
2020-11-10 4ff6b73c2bb57764db2bcd8212d82f028e25e36d
提交 | 用户 | age
2f6253 1 import type { PropType } from 'vue';
2 import type { Menu } from '/@/router/types';
3
4 import { computed, defineComponent, unref, ref, onMounted, watch } from 'vue';
5 import { BasicMenu } from '/@/components/Menu/index';
6 import Logo from '/@/layouts/Logo.vue';
7
8 import { MenuModeEnum, MenuSplitTyeEnum, MenuTypeEnum } from '/@/enums/menuEnum';
9
10 // store
11 import { appStore } from '/@/store/modules/app';
12 import { menuStore } from '/@/store/modules/menu';
13
14 import {
15   getMenus,
16   getFlatMenus,
17   getShallowMenus,
18   getChildrenMenus,
19   getFlatChildrenMenus,
20   getCurrentParentPath,
21 } from '/@/router/menus/index';
22 import { useRouter } from 'vue-router';
23 import { useThrottle } from '/@/hooks/core/useThrottle';
24 import { permissionStore } from '/@/store/modules/permission';
6bffdb 25 // import { useTabs } from '/@/hooks/web/useTabs';
V 26 // import { PageEnum } from '/@/enums/pageEnum';
2f6253 27
28 // import
29 export default defineComponent({
30   name: 'DefaultLayoutMenu',
31   props: {
32     theme: {
33       type: String as PropType<string>,
34       default: '',
35     },
36     splitType: {
37       type: Number as PropType<MenuSplitTyeEnum>,
38       default: MenuSplitTyeEnum.NONE,
39     },
40     parentMenuPath: {
41       type: String as PropType<string>,
42       default: '',
43     },
44     showSearch: {
45       type: Boolean as PropType<boolean>,
46       default: true,
47     },
770283 48     isTop: {
V 49       type: Boolean as PropType<boolean>,
50       default: false,
51     },
2f6253 52     menuMode: {
53       type: [String] as PropType<MenuModeEnum | null>,
54       default: '',
55     },
56   },
57   setup(props) {
4ff6b7 58     // Menu array
2f6253 59     const menusRef = ref<Menu[]>([]);
4ff6b7 60     // flat menu array
2f6253 61     const flatMenusRef = ref<Menu[]>([]);
6bffdb 62     const { currentRoute, push } = useRouter();
2f6253 63
4ff6b7 64     // get app config
2f6253 65     const getProjectConfigRef = computed(() => {
66       return appStore.getProjectConfig;
67     });
68
4ff6b7 69     // get is Horizontal
2f6253 70     const getIsHorizontalRef = computed(() => {
71       return unref(getProjectConfigRef).menuSetting.mode === MenuModeEnum.HORIZONTAL;
72     });
73
74     const [throttleHandleSplitLeftMenu] = useThrottle(handleSplitLeftMenu, 50);
75
4ff6b7 76     // Route change split menu
2f6253 77     watch(
78       [() => unref(currentRoute).path, () => props.splitType],
79       async ([path, splitType]: [string, MenuSplitTyeEnum]) => {
80         if (splitType !== MenuSplitTyeEnum.LEFT && !unref(getIsHorizontalRef)) return;
81         const parentPath = await getCurrentParentPath(path);
82         parentPath && throttleHandleSplitLeftMenu(parentPath);
83       },
84       {
85         immediate: true,
86       }
87     );
4f6b65 88
4ff6b7 89     // Menu changes
2f6253 90     watch(
4ff6b7 91       [() => permissionStore.getLastBuildMenuTimeState, () => permissionStore.getBackMenuListState],
2f6253 92       () => {
93         genMenus();
94       }
95     );
96
4ff6b7 97     // split Menu changes
2f6253 98     watch([() => appStore.getProjectConfig.menuSetting.split], () => {
99       if (props.splitType !== MenuSplitTyeEnum.LEFT && !unref(getIsHorizontalRef)) return;
100       genMenus();
101     });
102
4ff6b7 103     // Handle left menu split
2f6253 104     async function handleSplitLeftMenu(parentPath: string) {
105       const isSplitMenu = unref(getProjectConfigRef).menuSetting.split;
106       if (!isSplitMenu) return;
107       const { splitType } = props;
4ff6b7 108       // spilt mode left
2f6253 109       if (splitType === MenuSplitTyeEnum.LEFT) {
110         const children = await getChildrenMenus(parentPath);
96c10d 111         if (!children) {
V 112           appStore.commitProjectConfigState({
113             menuSetting: {
4f6b65 114               hidden: false,
96c10d 115             },
V 116           });
117           flatMenusRef.value = [];
118           menusRef.value = [];
119           return;
120         }
2f6253 121         const flatChildren = await getFlatChildrenMenus(children);
96c10d 122         appStore.commitProjectConfigState({
V 123           menuSetting: {
4f6b65 124             hidden: true,
96c10d 125           },
V 126         });
2f6253 127         flatMenusRef.value = flatChildren;
128         menusRef.value = children;
129       }
130     }
131
4ff6b7 132     // get menus
2f6253 133     async function genMenus() {
134       const isSplitMenu = unref(getProjectConfigRef).menuSetting.split;
135
4ff6b7 136       // normal mode
2f6253 137       const { splitType } = props;
138       if (splitType === MenuSplitTyeEnum.NONE || !isSplitMenu) {
139         flatMenusRef.value = await getFlatMenus();
140         menusRef.value = await getMenus();
141         return;
142       }
143
4ff6b7 144       // split-top
2f6253 145       if (splitType === MenuSplitTyeEnum.TOP) {
146         const parentPath = await getCurrentParentPath(unref(currentRoute).path);
147         menuStore.commitCurrentTopSplitMenuPathState(parentPath);
148         const shallowMenus = await getShallowMenus();
149
150         flatMenusRef.value = shallowMenus;
151         menusRef.value = shallowMenus;
152         return;
153       }
154     }
155
156     function handleMenuClick(menu: Menu) {
157       const { path } = menu;
158       if (path) {
159         const { splitType } = props;
4ff6b7 160         // split mode top
2f6253 161         if (splitType === MenuSplitTyeEnum.TOP) {
162           menuStore.commitCurrentTopSplitMenuPathState(path);
163         }
6bffdb 164         push(path);
2f6253 165       }
166     }
167
168     async function beforeMenuClickFn(menu: Menu) {
169       const { meta: { externalLink } = {} } = menu;
170
171       if (externalLink) {
172         window.open(externalLink, '_blank');
173         return false;
174       }
175
176       return true;
177     }
178
179     function handleClickSearchInput() {
180       if (menuStore.getCollapsedState) {
181         menuStore.commitCollapsedState(false);
182       }
183     }
184
185     const showSearchRef = computed(() => {
186       const { showSearch, type, mode } = unref(getProjectConfigRef).menuSetting;
187       return (
188         showSearch &&
189         props.showSearch &&
190         !(type === MenuTypeEnum.MIX && mode === MenuModeEnum.HORIZONTAL)
191       );
192     });
193
4f6b65 194     onMounted(() => {
V 195       genMenus();
196     });
197
2f6253 198     return () => {
199       const {
200         showLogo,
e79e54 201         menuSetting: {
V 202           type: menuType,
203           mode,
204           theme,
205           collapsed,
206           collapsedShowTitle,
207           collapsedShowSearch,
4ff6b7 208           accordion,
e79e54 209         },
2f6253 210       } = unref(getProjectConfigRef);
211
212       const isSidebarType = menuType === MenuTypeEnum.SIDEBAR;
213       const isShowLogo = showLogo && isSidebarType;
214       const themeData = props.theme || theme;
215       return (
216         <BasicMenu
217           beforeClickFn={beforeMenuClickFn}
218           onMenuClick={handleMenuClick}
219           type={menuType}
220           mode={props.menuMode || mode}
221           class="layout-menu"
5737e4 222           collapsedShowTitle={collapsedShowTitle}
2f6253 223           theme={themeData}
224           showLogo={isShowLogo}
e79e54 225           search={unref(showSearchRef) && (collapsedShowSearch ? true : !collapsed)}
2f6253 226           items={unref(menusRef)}
227           flatItems={unref(flatMenusRef)}
228           onClickSearchInput={handleClickSearchInput}
229           appendClass={props.splitType === MenuSplitTyeEnum.TOP}
770283 230           isTop={props.isTop}
4ff6b7 231           accordion={accordion}
2f6253 232         >
233           {{
234             header: () =>
235               isShowLogo && (
4f6b65 236                 <Logo
V 237                   showTitle={!collapsed}
238                   class={[`layout-menu__logo`, themeData]}
239                   theme={themeData}
240                 />
2f6253 241               ),
242           }}
243         </BasicMenu>
244       );
245     };
246   },
247 });