| // Licensed to the Apache Software Foundation (ASF) under one |
| // or more contributor license agreements. See the NOTICE file |
| // distributed with this work for additional information |
| // regarding copyright ownership. The ASF licenses this file |
| // to you under the Apache License, Version 2.0 (the |
| // "License"); you may not use this file except in compliance |
| // with the License. You may obtain a copy of the License at |
| // |
| // http://www.apache.org/licenses/LICENSE-2.0 |
| // |
| // Unless required by applicable law or agreed to in writing, |
| // software distributed under the License is distributed on an |
| // "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
| // KIND, either express or implied. See the License for the |
| // specific language governing permissions and limitations |
| // under the License. |
| |
| <template> |
| <a-menu |
| :mode="mode" |
| :theme="theme" |
| :openKeys="openKeys" |
| v-model:selectedKeys="selectedKeys" |
| @click="selectMenu" |
| @openChange="onOpenChange" |
| > |
| <template v-for="(item, index) in menuData" :key="index"> |
| <a-sub-menu v-if="item.children && !item.hideChildrenInMenu" :key="item.path"> |
| <template #title> |
| <span> |
| <render-icon |
| v-if="item.meta.icon && typeof (item.meta.icon) === 'string'" |
| :icon="item.meta.icon" |
| @click="() => { handleClickParentMenu(item) }" /> |
| <span @click="() => { handleClickParentMenu(item) }">{{ $t(item.meta.title) }}</span> |
| </span> |
| </template> |
| <template v-for="children in item.children" :key="children.path"> |
| <a-menu-item :key="children.path" v-if="!children.hidden"> |
| <router-link :to="{ name: children.name, target: children.meta.target || null }"> |
| <render-icon |
| v-if="children.meta.icon && typeof (children.meta.icon) === 'string'" |
| :icon="children.meta.icon" /> |
| <font-awesome-icon |
| v-else-if="children.meta.icon && Array.isArray(children.meta.icon)" |
| :icon="children.meta.icon" |
| class="anticon" |
| :style="[$store.getters.darkMode ? { color: 'rgba(255, 255, 255, 0.65)' } : { color: '#888' }]" /> |
| <render-icon v-else :svgIcon="children.meta.icon" /> |
| <span>{{ $t(children.meta.title) }}</span> |
| </router-link> |
| </a-menu-item> |
| </template> |
| </a-sub-menu> |
| <a-menu-item v-else :key="item.path"> |
| <router-link :to="{ name: item.name, target: item.meta.target || null }"> |
| <render-icon |
| v-if="item.meta.icon && typeof (item.meta.icon) === 'string'" |
| :icon="item.meta.icon" |
| @click="() => { handleClickParentMenu(item) }" /> |
| <span>{{ $t(item.meta.title) }}</span> |
| </router-link> |
| </a-menu-item> |
| </template> |
| </a-menu> |
| </template> |
| |
| <script> |
| |
| export default { |
| name: 'SMenu', |
| props: { |
| menu: { |
| type: Array, |
| required: true |
| }, |
| theme: { |
| type: String, |
| required: false, |
| default: 'dark' |
| }, |
| mode: { |
| type: String, |
| required: false, |
| default: 'inline' |
| }, |
| collapsed: { |
| type: Boolean, |
| required: false, |
| default: false |
| } |
| }, |
| data () { |
| return { |
| openKeys: [], |
| selectedKeys: [], |
| cachedOpenKeys: [], |
| cachedPath: null |
| } |
| }, |
| computed: { |
| rootSubmenuKeys: vm => { |
| const keys = [] |
| vm.menu.forEach(item => keys.push(item.path)) |
| return keys |
| }, |
| menuData () { |
| return this.menu.filter(item => !item.hidden) |
| } |
| }, |
| created () { |
| this.updateMenu() |
| }, |
| watch: { |
| collapsed (val) { |
| this.openKeys = val ? [] : this.cachedOpenKeys |
| }, |
| '$route.fullPath': function () { |
| this.updateMenu() |
| } |
| }, |
| methods: { |
| selectMenu (obj) { |
| this.selectedKeys = [obj.key] |
| }, |
| onOpenChange (openKeys) { |
| const latestOpenKey = openKeys.find(key => this.openKeys.indexOf(key) === -1) |
| if (this.rootSubmenuKeys.indexOf(latestOpenKey) === -1) { |
| this.openKeys = openKeys |
| } else { |
| this.openKeys = latestOpenKey ? [latestOpenKey] : [] |
| } |
| }, |
| updateMenu () { |
| const routes = this.$route.matched.concat() |
| |
| if (routes.length >= 4 && this.$route.meta.hidden) { |
| routes.pop() |
| this.selectedKeys = [routes[2].path] |
| } else { |
| this.selectedKeys = [routes.pop().path] |
| } |
| |
| const openKeys = [] |
| if (this.mode === 'inline') { |
| routes.forEach(item => { |
| openKeys.push(item.path) |
| }) |
| } |
| |
| this.cachedPath = this.selectedKeys[0] |
| this.cachedOpenKeys = openKeys |
| if (!this.collapsed) { |
| this.openKeys = openKeys |
| } |
| }, |
| handleClickParentMenu (menuItem) { |
| if (this.cachedPath === menuItem.redirect) { |
| return |
| } |
| if (menuItem.redirect) { |
| this.cachedPath = menuItem.redirect |
| setTimeout(() => this.$router.push({ path: menuItem.path })) |
| } |
| } |
| } |
| } |
| </script> |
| |
| <style> |
| .sider .ant-menu-vertical .ant-menu-item { |
| margin-right: 0; |
| } |
| </style> |