铜陵经侦
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

137 lines
4.5 KiB

4 months ago
<!--
* 传统菜单-递归菜单
*
* @Author: 1024创新实验室-主任:卓大
* @Date: 2022-09-06 20:29:12
* @Wechat: zhuda1024
* @Email: lab1024@163.com
* @Copyright 1024创新实验室 ( https://1024lab.net ),Since 2012
-->
<template>
<a-menu :open-keys="openKeys" v-model:selectedKeys="selectedKeys" class="smart-menu" mode="inline" :theme="theme" @openChange="onOpenChange">
<template v-for="item in menuTree" :key="item.menuId">
<template v-if="item.visibleFlag && !item.disabledFlag">
<template v-if="$lodash.isEmpty(item.children)">
<a-menu-item :key="item.menuId" @click="turnToPage(item)">
<template #icon>
1 month ago
<component :is="resolveMenuIcon($antIcons, item.icon)" />
4 months ago
</template>
{{ item.menuName }}
</a-menu-item>
</template>
<template v-else>
<SubMenu :menu-info="item" :key="item.menuId" @turnToPage="turnToPage" />
</template>
</template>
</template>
</a-menu>
</template>
<script setup>
import _ from 'lodash';
import { computed, ref, watch } from 'vue';
10 hours ago
import { useRoute, useRouter } from 'vue-router';
4 months ago
import SubMenu from './sub-menu.vue';
1 month ago
import { resolveMenuIcon } from '/@/utils/menu-icon-util';
import { getSidebarMenuTree } from '/@/utils/portal-menu-util';
4 months ago
import { useAppConfigStore } from '/@/store/modules/system/app-config';
1 month ago
import { usePortalModuleStore } from '/@/store/modules/system/portal-module';
4 months ago
import { useUserStore } from '/@/store/modules/system/user';
const theme = computed(() => useAppConfigStore().$state.sideMenuTheme);
const flatPattern = computed(() => useAppConfigStore().$state.flatPattern);
const props = defineProps({
collapsed: {
type: Boolean,
default: false,
},
});
1 month ago
const portalStore = usePortalModuleStore();
portalStore.initFromStorage();
const menuTree = computed(() =>
getSidebarMenuTree(useUserStore().getMenuTree || [], portalStore.getActiveTopModuleId),
);
const rootSubmenuKeys = computed(() => menuTree.value.map((item) => item.menuId));
4 months ago
//展开的菜单
let currentRoute = useRoute();
const selectedKeys = ref([]);
const openKeys = ref([]);
10 hours ago
// 与 useRoute 使用同一个已安装的路由实例,避免热更新后菜单与页面不同步。
const router = useRouter();
4 months ago
// 页面跳转
function turnToPage(menu) {
useUserStore().deleteKeepAliveIncludes(menu.menuId.toString());
router.push({ path: menu.path });
}
/**
* SmartAdmin中 router的name 就是 后端存储menu的id
* 所以此处可以直接监听路由,根据路由更新菜单的选中和展开
*/
function updateOpenKeysAndSelectKeys() {
// 更新选中
selectedKeys.value = [_.toNumber(currentRoute.name)];
10 hours ago
// 只展开当前侧栏中的祖先目录,门户一级模块不在侧栏中。
4 months ago
//获取需要展开的menu key集合
let menuParentIdListMap = useUserStore().getMenuParentIdListMap;
let parentList = menuParentIdListMap.get(currentRoute.name) || [];
// 如果是折叠菜单的话,则不需要设置openkey
if (!props.collapsed) {
10 hours ago
const submenuKeys = new Set();
function collectSubmenus(items) {
for (const item of items) {
if (item.children?.length && item.visibleFlag && !item.disabledFlag) {
submenuKeys.add(Number(item.menuId));
collectSubmenus(item.children);
}
}
}
collectSubmenus(menuTree.value);
const needOpenKeys = parentList.map((item) => Number(item.name)).filter((key) => submenuKeys.has(key));
// 单目录模式切换页面时关闭无关目录,不能把上个页面的风险预警一直保留。
openKeys.value = flatPattern.value
? _.union(openKeys.value.filter((key) => submenuKeys.has(key)), needOpenKeys)
: needOpenKeys;
4 months ago
}
}
watch(
10 hours ago
[() => currentRoute.name, menuTree, flatPattern],
4 months ago
() => {
updateOpenKeysAndSelectKeys();
},
{
immediate: true,
}
);
10 hours ago
function onOpenChange(openKeysParams) {
if (flatPattern.value) {
openKeys.value = openKeysParams;
return;
}
const latestOpenKey = openKeysParams.find((key) => !openKeys.value.includes(key));
if (!rootSubmenuKeys.value.includes(latestOpenKey)) {
openKeys.value = openKeysParams;
} else {
openKeys.value = latestOpenKey !== undefined ? [latestOpenKey] : [];
}
4 months ago
}
defineExpose({
updateOpenKeysAndSelectKeys,
});
</script>
<style lang="less" scoped>
.smart-menu {
position: relative;
}
</style>