menu.js 6.96 KB
Newer Older
wb-ct393452's avatar
wb-ct393452 committed
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29
/**
 * 该插件可根据菜单配置自动生成 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: '监控中心'}}
30
 *
wb-ct393452's avatar
wb-ct393452 committed
31 32 33
 *   }
 * }
 **/
34 35 36
import Menu from 'ant-design-vue/es/menu';
import Icon from 'ant-design-vue/es/icon';
import { getUserInfo } from '@/utils';
wb-ct393452's avatar
wb-ct393452 committed
37 38 39 40

const { Item, SubMenu } = Menu;

export default {
41
    name: 'IMenu',
wb-ct393452's avatar
wb-ct393452 committed
42 43 44 45 46 47 48 49
    props: {
        options: {
            type: Array,
            required: true,
        },
        theme: {
            type: String,
            required: false,
50
            default: 'dark',
wb-ct393452's avatar
wb-ct393452 committed
51 52 53 54
        },
        mode: {
            type: String,
            required: false,
55
            default: 'inline',
wb-ct393452's avatar
wb-ct393452 committed
56 57 58 59 60 61 62 63 64 65 66 67 68
        },
        collapsed: {
            type: Boolean,
            required: false,
            default: false,
        },
        i18n: Object,
    },
    data() {
        return {
            selectedKeys: [],
            sOpenKeys: [],
            cachedOpenKeys: [],
69
            menuData: [],
wb-ct393452's avatar
wb-ct393452 committed
70 71 72 73
        };
    },
    computed: {
        menuTheme() {
74
            return this.theme == 'light' ? this.theme : 'dark';
wb-ct393452's avatar
wb-ct393452 committed
75 76 77
        },
    },
    created() {
78 79 80 81 82 83 84 85 86 87
        const { menuList } = getUserInfo();
        this.menuData = menuList.filter(i => i.menuType === 'MENU');
        this.updateMenu();
        // // 自定义国际化配置
        // if (this.i18n && this.i18n.messages) {
        //     const messages = this.i18n.messages;
        //     Object.keys(messages).forEach(key => {
        //         this.$i18n.mergeLocaleMessage(key, messages[key]);
        //     });
        // }
wb-ct393452's avatar
wb-ct393452 committed
88 89 90 91 92
    },
    watch: {
        i18n(val) {
            if (val && val.messages) {
                const messages = this.i18n.messages;
93
                Object.keys(messages).forEach(key => {
wb-ct393452's avatar
wb-ct393452 committed
94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109
                    this.$i18n.mergeLocaleMessage(key, messages[key]);
                });
            }
        },
        collapsed(val) {
            if (val) {
                this.cachedOpenKeys = this.sOpenKeys;
                this.sOpenKeys = [];
            } else {
                this.sOpenKeys = this.cachedOpenKeys;
            }
        },
        $route: function() {
            this.updateMenu();
        },
        sOpenKeys(val) {
110 111
            this.$emit('openChange', val);
            this.$emit('update:openKeys', val);
wb-ct393452's avatar
wb-ct393452 committed
112 113 114
        },
    },
    methods: {
115 116
        renderIcon(h, icon, key) {
            if (this.$scopedSlots.icon && icon && icon !== 'none') {
wb-ct393452's avatar
wb-ct393452 committed
117
                const vnodes = this.$scopedSlots.icon({ icon, key });
118
                vnodes.forEach(vnode => {
wb-ct393452's avatar
wb-ct393452 committed
119
                    vnode.data.class = vnode.data.class ? vnode.data.class : [];
120
                    vnode.data.class.push('anticon');
wb-ct393452's avatar
wb-ct393452 committed
121 122 123
                });
                return vnodes;
            }
124
            return !icon || icon == 'none' ? null : h(Icon, { props: { type: icon } });
wb-ct393452's avatar
wb-ct393452 committed
125
        },
126 127 128 129 130
        renderMenuItem(h, menu) {
            const tag = 'router-link';
            const config = {
                props: { to: menu.path },
                attrs: { style: 'overflow:hidden;white-space:normal;text-overflow:clip;' },
wb-ct393452's avatar
wb-ct393452 committed
131
            };
132 133 134

            return h(Item, { key: menu.menuId }, [
                h(tag, config, [this.renderIcon(h, menu.menuIcon, menu.menuId), menu.menuName]),
wb-ct393452's avatar
wb-ct393452 committed
135 136
            ]);
        },
137 138
        renderSubMenu(h, menu) {
            const subItem = [
wb-ct393452's avatar
wb-ct393452 committed
139
                h(
140 141 142 143 144 145
                    'span',
                    {
                        slot: 'title',
                        attrs: { style: 'overflow:hidden;white-space:normal;text-overflow:clip;' },
                    },
                    [this.renderIcon(h, menu.menuIcon, menu.menuId), menu.menuName],
wb-ct393452's avatar
wb-ct393452 committed
146 147
                ),
            ];
148 149 150
            const itemArr = [];
            menu.children.forEach(item => {
                itemArr.push(this.renderItem(h, item));
wb-ct393452's avatar
wb-ct393452 committed
151
            });
152 153 154 155 156 157
            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);
wb-ct393452's avatar
wb-ct393452 committed
158
        },
159
        renderMenu(h, menuTree) {
wb-ct393452's avatar
wb-ct393452 committed
160
            let menuArr = [];
161 162
            menuTree.forEach((menu, i) => {
                menuArr.push(this.renderItem(h, menu));
wb-ct393452's avatar
wb-ct393452 committed
163 164 165
            });
            return menuArr;
        },
166

wb-ct393452's avatar
wb-ct393452 committed
167 168
        updateMenu() {
            this.selectedKeys = this.getSelectedKey(this.$route);
169 170 171 172 173 174 175 176 177 178 179

            // let openKeys = matchedRoutes.map(item => item.path);

            // openKeys = openKeys.slice(0, openKeys.length - 1);

            // if (!fastEqual(openKeys, this.sOpenKeys)) {
            //     this.collapsed || this.mode === 'horizontal'
            //         ? (this.cachedOpenKeys = openKeys)
            //         : (this.sOpenKeys = openKeys);
            // }
            this.sOpenKeys = this.getOpenKeysByPath(this.$route.path);
wb-ct393452's avatar
wb-ct393452 committed
180 181
        },
        getSelectedKey(route) {
182 183 184 185 186 187 188
            const { path } = route;
            return [this.menuData.find(m => m.menuUrl === path).menuId];
        },

        getOpenKeysByPath(path) {
            const { menuList } = getUserInfo();
            const { parentMenuId } = this.menuData.find(m => m.menuUrl === path);
水落(YangLei)'s avatar
水落(YangLei) committed
189
            if (parentMenuId === 0) return [];
190 191 192 193 194 195 196 197 198 199 200
            const parentMenus = [parentMenuId];
            const res = [parentMenuId];
            while (parentMenus.length) {
                const menuId = parentMenus.pop();
                const parentMenu = menuList.find(m => m.menuId === menuId);
                if (parentMenu.parentMenuId !== 0) {
                    parentMenus.push(parentMenu.parentMenuId);
                    res.push(parentMenu.parentMenuId);
                }
            }
            return res;
wb-ct393452's avatar
wb-ct393452 committed
201 202 203 204 205 206 207 208 209 210
        },
    },
    render(h) {
        return h(
            Menu,
            {
                props: {
                    theme: this.menuTheme,
                    mode: this.$props.mode,
                    selectedKeys: this.selectedKeys,
211
                    openKeys: this.sOpenKeys,
wb-ct393452's avatar
wb-ct393452 committed
212 213
                },
                on: {
214
                    'update:openKeys': val => {
wb-ct393452's avatar
wb-ct393452 committed
215 216
                        this.sOpenKeys = val;
                    },
217
                    click: obj => {
wb-ct393452's avatar
wb-ct393452 committed
218
                        obj.selectedKeys = [obj.key];
219
                        this.$emit('select', obj);
wb-ct393452's avatar
wb-ct393452 committed
220 221 222
                    },
                },
            },
223
            this.renderMenu(h, this.options),
wb-ct393452's avatar
wb-ct393452 committed
224 225 226
        );
    },
};