Blame view

src/layouts/default/menu/LayoutMenu.tsx 6.75 KB
陈文彬 authored
1
2
3
4
5
import type { PropType } from 'vue';
import type { Menu } from '/@/router/types';

import { computed, defineComponent, unref, ref, onMounted, watch } from 'vue';
import { BasicMenu } from '/@/components/Menu/index';
vben authored
6
import Logo from '/@/layouts/logo/index.vue';
陈文彬 authored
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25

import { MenuModeEnum, MenuSplitTyeEnum, MenuTypeEnum } from '/@/enums/menuEnum';

// store
import { appStore } from '/@/store/modules/app';
import { menuStore } from '/@/store/modules/menu';

import {
  getMenus,
  getFlatMenus,
  getShallowMenus,
  getChildrenMenus,
  getFlatChildrenMenus,
  getCurrentParentPath,
} from '/@/router/menus/index';
import { useRouter } from 'vue-router';
import { useThrottle } from '/@/hooks/core/useThrottle';
import { permissionStore } from '/@/store/modules/permission';
vben authored
26
import './index.less';
陈文彬 authored
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
export default defineComponent({
  name: 'DefaultLayoutMenu',
  props: {
    theme: {
      type: String as PropType<string>,
      default: '',
    },
    splitType: {
      type: Number as PropType<MenuSplitTyeEnum>,
      default: MenuSplitTyeEnum.NONE,
    },
    parentMenuPath: {
      type: String as PropType<string>,
      default: '',
    },
    showSearch: {
      type: Boolean as PropType<boolean>,
      default: true,
    },
46
47
48
49
    isTop: {
      type: Boolean as PropType<boolean>,
      default: false,
    },
陈文彬 authored
50
51
52
53
54
55
    menuMode: {
      type: [String] as PropType<MenuModeEnum | null>,
      default: '',
    },
  },
  setup(props) {
56
    // Menu array
陈文彬 authored
57
    const menusRef = ref<Menu[]>([]);
58
    // flat menu array
陈文彬 authored
59
    const flatMenusRef = ref<Menu[]>([]);
60
    const { currentRoute, push } = useRouter();
陈文彬 authored
61
62
    // get app config
陈文彬 authored
63
64
65
66
    const getProjectConfigRef = computed(() => {
      return appStore.getProjectConfig;
    });
67
    // get is Horizontal
陈文彬 authored
68
69
70
71
72
73
    const getIsHorizontalRef = computed(() => {
      return unref(getProjectConfigRef).menuSetting.mode === MenuModeEnum.HORIZONTAL;
    });

    const [throttleHandleSplitLeftMenu] = useThrottle(handleSplitLeftMenu, 50);
74
    // Route change split menu
陈文彬 authored
75
76
77
78
79
80
81
82
83
84
85
    watch(
      [() => unref(currentRoute).path, () => props.splitType],
      async ([path, splitType]: [string, MenuSplitTyeEnum]) => {
        if (splitType !== MenuSplitTyeEnum.LEFT && !unref(getIsHorizontalRef)) return;
        const parentPath = await getCurrentParentPath(path);
        parentPath && throttleHandleSplitLeftMenu(parentPath);
      },
      {
        immediate: true,
      }
    );
86
87
    // Menu changes
陈文彬 authored
88
    watch(
89
      [() => permissionStore.getLastBuildMenuTimeState, () => permissionStore.getBackMenuListState],
陈文彬 authored
90
91
92
93
94
      () => {
        genMenus();
      }
    );
95
    // split Menu changes
陈文彬 authored
96
97
98
99
100
    watch([() => appStore.getProjectConfig.menuSetting.split], () => {
      if (props.splitType !== MenuSplitTyeEnum.LEFT && !unref(getIsHorizontalRef)) return;
      genMenus();
    });
101
    // Handle left menu split
陈文彬 authored
102
103
104
105
    async function handleSplitLeftMenu(parentPath: string) {
      const isSplitMenu = unref(getProjectConfigRef).menuSetting.split;
      if (!isSplitMenu) return;
      const { splitType } = props;
106
      // spilt mode left
陈文彬 authored
107
108
      if (splitType === MenuSplitTyeEnum.LEFT) {
        const children = await getChildrenMenus(parentPath);
109
110
111
        if (!children) {
          appStore.commitProjectConfigState({
            menuSetting: {
112
              hidden: false,
113
114
115
116
117
118
            },
          });
          flatMenusRef.value = [];
          menusRef.value = [];
          return;
        }
陈文彬 authored
119
        const flatChildren = await getFlatChildrenMenus(children);
120
121
        appStore.commitProjectConfigState({
          menuSetting: {
122
            hidden: true,
123
124
          },
        });
陈文彬 authored
125
126
127
128
129
        flatMenusRef.value = flatChildren;
        menusRef.value = children;
      }
    }
130
    // get menus
陈文彬 authored
131
132
133
    async function genMenus() {
      const isSplitMenu = unref(getProjectConfigRef).menuSetting.split;
134
      // normal mode
陈文彬 authored
135
136
137
138
139
140
141
      const { splitType } = props;
      if (splitType === MenuSplitTyeEnum.NONE || !isSplitMenu) {
        flatMenusRef.value = await getFlatMenus();
        menusRef.value = await getMenus();
        return;
      }
142
      // split-top
陈文彬 authored
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
      if (splitType === MenuSplitTyeEnum.TOP) {
        const parentPath = await getCurrentParentPath(unref(currentRoute).path);
        menuStore.commitCurrentTopSplitMenuPathState(parentPath);
        const shallowMenus = await getShallowMenus();

        flatMenusRef.value = shallowMenus;
        menusRef.value = shallowMenus;
        return;
      }
    }

    function handleMenuClick(menu: Menu) {
      const { path } = menu;
      if (path) {
        const { splitType } = props;
158
        // split mode top
陈文彬 authored
159
160
161
        if (splitType === MenuSplitTyeEnum.TOP) {
          menuStore.commitCurrentTopSplitMenuPathState(path);
        }
162
        push(path);
陈文彬 authored
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
      }
    }

    async function beforeMenuClickFn(menu: Menu) {
      const { meta: { externalLink } = {} } = menu;

      if (externalLink) {
        window.open(externalLink, '_blank');
        return false;
      }

      return true;
    }

    function handleClickSearchInput() {
      if (menuStore.getCollapsedState) {
        menuStore.commitCollapsedState(false);
      }
    }

    const showSearchRef = computed(() => {
      const { showSearch, type, mode } = unref(getProjectConfigRef).menuSetting;
      return (
        showSearch &&
        props.showSearch &&
        !(type === MenuTypeEnum.MIX && mode === MenuModeEnum.HORIZONTAL)
      );
    });
192
193
194
195
    onMounted(() => {
      genMenus();
    });
陈文彬 authored
196
197
198
    return () => {
      const {
        showLogo,
vben authored
199
200
201
202
203
204
205
        menuSetting: {
          type: menuType,
          mode,
          theme,
          collapsed,
          collapsedShowTitle,
          collapsedShowSearch,
206
          accordion,
vben authored
207
        },
陈文彬 authored
208
209
210
211
212
213
214
215
216
217
218
219
      } = unref(getProjectConfigRef);

      const isSidebarType = menuType === MenuTypeEnum.SIDEBAR;
      const isShowLogo = showLogo && isSidebarType;
      const themeData = props.theme || theme;
      return (
        <BasicMenu
          beforeClickFn={beforeMenuClickFn}
          onMenuClick={handleMenuClick}
          type={menuType}
          mode={props.menuMode || mode}
          class="layout-menu"
220
          collapsedShowTitle={collapsedShowTitle}
陈文彬 authored
221
222
          theme={themeData}
          showLogo={isShowLogo}
vben authored
223
          search={unref(showSearchRef) && (collapsedShowSearch ? true : !collapsed)}
陈文彬 authored
224
225
226
227
          items={unref(menusRef)}
          flatItems={unref(flatMenusRef)}
          onClickSearchInput={handleClickSearchInput}
          appendClass={props.splitType === MenuSplitTyeEnum.TOP}
228
          isTop={props.isTop}
229
          accordion={accordion}
陈文彬 authored
230
231
232
233
        >
          {{
            header: () =>
              isShowLogo && (
234
235
236
237
238
                <Logo
                  showTitle={!collapsed}
                  class={[`layout-menu__logo`, themeData]}
                  theme={themeData}
                />
陈文彬 authored
239
240
241
242
243
244
245
              ),
          }}
        </BasicMenu>
      );
    };
  },
});