/** * 该插件可根据菜单配置自动生成 ANTD menu组件 * menuOptions示例: * [ * { * name: '菜单名称', * path: '菜单路由', * meta: { * icon: '菜单图标', * invisible: 'boolean, 是否不可见, 默认 false', * }, * children: [子菜单配置] * }, * { * name: '菜单名称', * path: '菜单路由', * meta: { * icon: '菜单图标', * invisible: 'boolean, 是否不可见, 默认 false', * }, * children: [子菜单配置] * } * ] * * i18n: 国际化配置。系统默认会根据 options route配置的 path 和 name 生成英文以及中文的国际化配置,如需自定义或增加其他语言,配置 * 此项即可。如: * i18n: { * messages: { * zh_CN: {dashboard: {name: '监控中心'}} * * } * } **/ import Menu from 'ant-design-vue/es/menu'; import Icon from 'ant-design-vue/es/icon'; import { getUserInfo } from '@/utils'; import { mapState } from 'vuex'; const { Item, SubMenu } = Menu; export default { name: 'IMenu', props: { options: { 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, }, i18n: Object, }, data() { return { selectedKeys: [], sOpenKeys: [], cachedOpenKeys: [], menuData: [], allMenuList: [], }; }, computed: { ...mapState('settingModule', ['layout']), menuTheme() { return this.theme == 'light' ? this.theme : 'dark'; }, }, created() { const { menuList } = getUserInfo(); // 增加查询速度 this.menuData = menuList.filter(i => i.menuType === 'MENU'); this.allMenuList = menuList; this.updateMenu(); }, watch: { i18n(val) { if (val && val.messages) { const messages = this.i18n.messages; Object.keys(messages).forEach(key => { this.$i18n.mergeLocaleMessage(key, messages[key]); }); } }, collapsed(val) { if (val) { this.cachedOpenKeys = this.sOpenKeys; this.sOpenKeys = []; } else { this.sOpenKeys = this.cachedOpenKeys; } }, sOpenKeys(val) { this.$emit('openChange', val); this.$emit('update:openKeys', val); }, }, methods: { renderIcon(h, icon, key) { if (this.$scopedSlots.icon && icon && icon !== 'none') { const vnodes = this.$scopedSlots.icon({ icon, key }); vnodes.forEach(vnode => { vnode.data.class = vnode.data.class ? vnode.data.class : []; vnode.data.class.push('anticon'); }); return vnodes; } return !icon || icon == 'none' ? null : h(Icon, { props: { type: icon } }); }, renderMenuItem(h, menu) { const tag = 'router-link'; const config = { props: { to: menu.menuUrl }, attrs: { style: 'overflow:hidden;white-space:normal;text-overflow:clip;' }, }; // 菜单 if (menu.menuType === 'MENU') { return h(Item, { key: menu.menuId }, [ h(tag, config, [this.renderIcon(h, menu.menuIcon, menu.menuId), menu.menuName]), ]); } return h(Item, { key: menu.menuId }, [ h( 'a', { attrs: { style: 'overflow:hidden;white-space:normal;text-overflow:clip;' }, on: { click(e) { e.preventDefault(); }, }, }, [this.renderIcon(h, menu.menuIcon, menu.menuId), menu.menuName], ), ]); }, renderSubMenu(h, menu) { const subItem = [ h( 'span', { slot: 'title', attrs: { style: 'overflow:hidden;white-space:normal;text-overflow:clip;' }, }, [this.renderIcon(h, menu.menuIcon, menu.menuId), menu.menuName], ), ]; const itemArr = []; menu.children.forEach(item => { itemArr.push(this.renderItem(h, item)); }); return h(SubMenu, { key: menu.menuId }, subItem.concat(itemArr)); }, renderItem(h, menu) { return menu.children && menu.children.length ? this.renderSubMenu(h, menu) : this.renderMenuItem(h, menu); }, renderMenu(h, menuTree) { const menuArr = []; menuTree.forEach(menu => { menuArr.push(this.renderItem(h, menu)); }); return menuArr; }, updateMenu() { this.selectedKeys = this.getSelectedKey(); // 混合模式 不管 if (this.layout !== 'mix') this.sOpenKeys = this.getOpenKeysByPath(this.$route.path); }, getSelectedKey() { const { path } = this.$route; let routeToMenu = this.menuData.find(m => m.menuUrl === path); if (this.layout !== 'mix') return [routeToMenu.menuId]; // 说明这是头部菜单 if (this.mode === 'horizontal') { let parentMenuId = routeToMenu.parentMenuId; while (parentMenuId !== 0) { routeToMenu = this.allMenuList.find(m => m.menuId === parentMenuId); parentMenuId = routeToMenu.parentMenuId; } return [routeToMenu.menuId]; } return []; }, getOpenKeysByPath(path) { const { parentMenuId } = this.menuData.find(m => m.menuUrl === path); if (parentMenuId === 0) return []; const parentMenus = [parentMenuId]; const res = [parentMenuId]; while (parentMenus.length) { const menuId = parentMenus.pop(); const parentMenu = this.allMenuList.find(m => m.menuId === menuId); if (parentMenu.parentMenuId !== 0) { parentMenus.push(parentMenu.parentMenuId); res.push(parentMenu.parentMenuId); } } return res; }, }, render(h) { return h( Menu, { props: { theme: this.menuTheme, mode: this.$props.mode, selectedKeys: this.selectedKeys, openKeys: this.sOpenKeys, }, on: { 'update:openKeys': val => { this.sOpenKeys = val; }, click: obj => { this.selectedKeys = [obj.key]; this.$emit('select', obj); }, }, }, this.renderMenu(h, this.options), ); }, };