menu.js 7.53 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';
水落(YangLei)'s avatar
水落(YangLei) committed
37
import { mapState } from 'vuex';
wb-ct393452's avatar
wb-ct393452 committed
38 39 40 41

const { Item, SubMenu } = Menu;

export default {
42
    name: 'IMenu',
wb-ct393452's avatar
wb-ct393452 committed
43 44 45 46 47 48 49 50
    props: {
        options: {
            type: Array,
            required: true,
        },
        theme: {
            type: String,
            required: false,
51
            default: 'dark',
wb-ct393452's avatar
wb-ct393452 committed
52 53 54 55
        },
        mode: {
            type: String,
            required: false,
56
            default: 'inline',
wb-ct393452's avatar
wb-ct393452 committed
57 58 59 60 61 62 63 64 65 66 67 68 69
        },
        collapsed: {
            type: Boolean,
            required: false,
            default: false,
        },
        i18n: Object,
    },
    data() {
        return {
            selectedKeys: [],
            sOpenKeys: [],
            cachedOpenKeys: [],
70
            menuData: [],
水落(YangLei)'s avatar
水落(YangLei) committed
71
            allMenuList: [],
wb-ct393452's avatar
wb-ct393452 committed
72 73 74
        };
    },
    computed: {
水落(YangLei)'s avatar
水落(YangLei) committed
75
        ...mapState('settingModule', ['layout']),
wb-ct393452's avatar
wb-ct393452 committed
76
        menuTheme() {
77
            return this.theme == 'light' ? this.theme : 'dark';
wb-ct393452's avatar
wb-ct393452 committed
78 79 80
        },
    },
    created() {
81
        const { menuList } = getUserInfo();
水落(YangLei)'s avatar
水落(YangLei) committed
82
        // 增加查询速度
83
        this.menuData = menuList.filter(i => i.menuType === 'MENU');
水落(YangLei)'s avatar
水落(YangLei) committed
84
        this.allMenuList = menuList;
85
        this.updateMenu();
wb-ct393452's avatar
wb-ct393452 committed
86 87 88 89 90
    },
    watch: {
        i18n(val) {
            if (val && val.messages) {
                const messages = this.i18n.messages;
91
                Object.keys(messages).forEach(key => {
wb-ct393452's avatar
wb-ct393452 committed
92 93 94 95 96 97 98 99 100 101 102 103 104
                    this.$i18n.mergeLocaleMessage(key, messages[key]);
                });
            }
        },
        collapsed(val) {
            if (val) {
                this.cachedOpenKeys = this.sOpenKeys;
                this.sOpenKeys = [];
            } else {
                this.sOpenKeys = this.cachedOpenKeys;
            }
        },
        sOpenKeys(val) {
105 106
            this.$emit('openChange', val);
            this.$emit('update:openKeys', val);
wb-ct393452's avatar
wb-ct393452 committed
107 108 109
        },
    },
    methods: {
110 111
        renderIcon(h, icon, key) {
            if (this.$scopedSlots.icon && icon && icon !== 'none') {
wb-ct393452's avatar
wb-ct393452 committed
112
                const vnodes = this.$scopedSlots.icon({ icon, key });
113
                vnodes.forEach(vnode => {
wb-ct393452's avatar
wb-ct393452 committed
114
                    vnode.data.class = vnode.data.class ? vnode.data.class : [];
115
                    vnode.data.class.push('anticon');
wb-ct393452's avatar
wb-ct393452 committed
116 117 118
                });
                return vnodes;
            }
119
            return !icon || icon == 'none' ? null : h(Icon, { props: { type: icon } });
wb-ct393452's avatar
wb-ct393452 committed
120
        },
水落(YangLei)'s avatar
水落(YangLei) committed
121

122 123
        renderMenuItem(h, menu) {
            const tag = 'router-link';
水落(YangLei)'s avatar
水落(YangLei) committed
124

125
            const config = {
水落(YangLei)'s avatar
水落(YangLei) committed
126
                props: { to: menu.menuUrl },
127
                attrs: { style: 'overflow:hidden;white-space:normal;text-overflow:clip;' },
wb-ct393452's avatar
wb-ct393452 committed
128
            };
水落(YangLei)'s avatar
水落(YangLei) committed
129 130 131 132 133 134
            // 菜单
            if (menu.menuType === 'MENU') {
                return h(Item, { key: menu.menuId }, [
                    h(tag, config, [this.renderIcon(h, menu.menuIcon, menu.menuId), menu.menuName]),
                ]);
            }
135 136

            return h(Item, { key: menu.menuId }, [
水落(YangLei)'s avatar
水落(YangLei) committed
137 138 139 140 141 142 143 144 145 146 147 148
                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],
                ),
wb-ct393452's avatar
wb-ct393452 committed
149 150
            ]);
        },
水落(YangLei)'s avatar
水落(YangLei) committed
151

152 153
        renderSubMenu(h, menu) {
            const subItem = [
wb-ct393452's avatar
wb-ct393452 committed
154
                h(
155 156 157 158 159 160
                    '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
161 162
                ),
            ];
163
            const itemArr = [];
水落(YangLei)'s avatar
水落(YangLei) committed
164

165 166
            menu.children.forEach(item => {
                itemArr.push(this.renderItem(h, item));
wb-ct393452's avatar
wb-ct393452 committed
167
            });
水落(YangLei)'s avatar
水落(YangLei) committed
168

169 170
            return h(SubMenu, { key: menu.menuId }, subItem.concat(itemArr));
        },
水落(YangLei)'s avatar
水落(YangLei) committed
171

172 173 174 175
        renderItem(h, menu) {
            return menu.children && menu.children.length
                ? this.renderSubMenu(h, menu)
                : this.renderMenuItem(h, menu);
wb-ct393452's avatar
wb-ct393452 committed
176
        },
水落(YangLei)'s avatar
水落(YangLei) committed
177

178
        renderMenu(h, menuTree) {
水落(YangLei)'s avatar
水落(YangLei) committed
179 180 181
            const menuArr = [];

            menuTree.forEach(menu => {
182
                menuArr.push(this.renderItem(h, menu));
wb-ct393452's avatar
wb-ct393452 committed
183
            });
水落(YangLei)'s avatar
水落(YangLei) committed
184

wb-ct393452's avatar
wb-ct393452 committed
185 186
            return menuArr;
        },
187

wb-ct393452's avatar
wb-ct393452 committed
188
        updateMenu() {
水落(YangLei)'s avatar
水落(YangLei) committed
189 190 191 192
            this.selectedKeys = this.getSelectedKey();
            // 混合模式 不管
            if (this.layout !== 'mix') this.sOpenKeys = this.getOpenKeysByPath(this.$route.path);
        },
193

水落(YangLei)'s avatar
水落(YangLei) committed
194 195 196
        getSelectedKey() {
            const { path } = this.$route;
            let routeToMenu = this.menuData.find(m => m.menuUrl === path);
197

水落(YangLei)'s avatar
水落(YangLei) committed
198
            if (this.layout !== 'mix') return [routeToMenu.menuId];
199

水落(YangLei)'s avatar
水落(YangLei) committed
200 201 202 203 204 205 206 207 208 209 210
            // 说明这是头部菜单
            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 [];
211 212 213 214
        },

        getOpenKeysByPath(path) {
            const { parentMenuId } = this.menuData.find(m => m.menuUrl === path);
水落(YangLei)'s avatar
水落(YangLei) committed
215
            if (parentMenuId === 0) return [];
216 217 218 219
            const parentMenus = [parentMenuId];
            const res = [parentMenuId];
            while (parentMenus.length) {
                const menuId = parentMenus.pop();
水落(YangLei)'s avatar
水落(YangLei) committed
220
                const parentMenu = this.allMenuList.find(m => m.menuId === menuId);
221 222 223 224 225 226
                if (parentMenu.parentMenuId !== 0) {
                    parentMenus.push(parentMenu.parentMenuId);
                    res.push(parentMenu.parentMenuId);
                }
            }
            return res;
wb-ct393452's avatar
wb-ct393452 committed
227 228 229 230 231 232 233 234 235 236
        },
    },
    render(h) {
        return h(
            Menu,
            {
                props: {
                    theme: this.menuTheme,
                    mode: this.$props.mode,
                    selectedKeys: this.selectedKeys,
237
                    openKeys: this.sOpenKeys,
wb-ct393452's avatar
wb-ct393452 committed
238 239
                },
                on: {
240
                    'update:openKeys': val => {
wb-ct393452's avatar
wb-ct393452 committed
241 242
                        this.sOpenKeys = val;
                    },
243
                    click: obj => {
水落(YangLei)'s avatar
水落(YangLei) committed
244
                        this.selectedKeys = [obj.key];
245
                        this.$emit('select', obj);
wb-ct393452's avatar
wb-ct393452 committed
246 247 248
                    },
                },
            },
249
            this.renderMenu(h, this.options),
wb-ct393452's avatar
wb-ct393452 committed
250 251 252
        );
    },
};