后台管理系统,前后端分离,不同角色看到的页面不同

1、我是用elementui框架做的前后端分离的后台管理系统;
2、管理系统中有不同的管理角色,而不同的角色看到的导航菜单不相同;
3、在展示的页面中,不同角色看到的数据不同、页面级的操作也有所区别,比如说,权限高的管理员除了查看数据还能进行一些操作:新增、删除,而权限低的用户只能看到数据,并不能看到操作按钮;

问题如上所述,欢迎各位同道中人不吝赐教!

导航菜单的数据格式

[{
        "menuId": 1,
        "parentId": 0,
        "parentName": null,
        "name": "运维管理",
        "path": "/",
        "perms": null,
        "type": null,
        "children": [{
            "menuId": 5,
            "parentId": 1,
            "parentName": null,
            "name": "工单管理",
            "path": "/",
            "perms": null,
            "type": null,
            "children": [{
                "menuId": 11,
                "parentId": 5,
                "parentName": null,
                "name": "装机工单",
                "path": "/mechanicOrder",
                "perms": null,
                "type": null,
                "children": [{
                    "menuId": 15,
                    "parentId": 11,
                    "parentName": null,
                    "name": "新建装机",
                    "path": "",
                    "perms": null,
                    "type": null,
                    "children": [{
                        "menuId": 22,
                        "parentId": 15,
                        "parentName": null,
                        "name": "修改撤机",
                        "path": "",
                        "perms": null,
                        "type": null,
                        "children": null
                    }]
                }, {
                    "menuId": 16,
                    "parentId": 11,
                    "parentName": null,
                    "name": "修改装机",
                    "path": "",
                    "perms": null,
                    "type": null,
                    "children": null
                }]
            }, {
                "menuId": 12,
                "parentId": 5,
                "parentName": null,
                "name": "配送工单",
                "path": "/dispatchOrder",
                "perms": null,
                "type": null,
                "children": [{
                    "menuId": 17,
                    "parentId": 12,
                    "parentName": null,
                    "name": "新增配送",
                    "path": "",
                    "perms": null,
                    "type": null,
                    "children": null
                }, {
                    "menuId": 18,
                    "parentId": 12,
                    "parentName": null,
                    "name": "修改配送",
                    "path": "",
                    "perms": null,
                    "type": null,
                    "children": null
                }]
            }, {
                "menuId": 13,
                "parentId": 5,
                "parentName": null,
                "name": "维修工单",
                "path": "/maintainOrder",
                "perms": null,
                "type": null,
                "children": [{
                    "menuId": 19,
                    "parentId": 13,
                    "parentName": null,
                    "name": "新增配送",
                    "path": "",
                    "perms": null,
                    "type": null,
                    "children": null
                }, {
                    "menuId": 20,
                    "parentId": 13,
                    "parentName": null,
                    "name": "修改配送",
                    "path": "",
                    "perms": null,
                    "type": null,
                    "children": null
                }]
            }, {
                "menuId": 14,
                "parentId": 5,
                "parentName": null,
                "name": "撤机工单",
                "path": "/leaveOrder",
                "perms": null,
                "type": null,
                "children": [{
                    "menuId": 21,
                    "parentId": 14,
                    "parentName": null,
                    "name": "新建撤机",
                    "path": "",
                    "perms": null,
                    "type": null,
                    "children": null
                }]
            }]
        }, {
            "menuId": 6,
            "parentId": 1,
            "parentName": null,
            "name": "点位管理",
            "path": "/",
            "perms": null,
            "type": null,
            "children": [{
                "menuId": 23,
                "parentId": 6,
                "parentName": null,
                "name": "点位管理",
                "path": "/",
                "perms": null,
                "type": null,
                "children": [{
                    "menuId": 24,
                    "parentId": 23,
                    "parentName": null,
                    "name": "新建点位",
                    "path": "",
                    "perms": null,
                    "type": null,
                    "children": null
                }, {
                    "menuId": 25,
                    "parentId": 23,
                    "parentName": null,
                    "name": "修改点位",
                    "path": "",
                    "perms": null,
                    "type": null,
                    "children": null
                }, {
                    "menuId": 26,
                    "parentId": 23,
                    "parentName": null,
                    "name": "删除点位",
                    "path": "",
                    "perms": null,
                    "type": null,
                    "children": null
                }, {
                    "menuId": 27,
                    "parentId": 23,
                    "parentName": null,
                    "name": "配置补货员",
                    "path": "",
                    "perms": null,
                    "type": null,
                    "children": null
                }, {
                    "menuId": 28,
                    "parentId": 23,
                    "parentName": null,
                    "name": "配置维修员",
                    "path": "",
                    "perms": null,
                    "type": null,
                    "children": null
                }]
            }]
        }, {
            "menuId": 7,
            "parentId": 1,
            "parentName": null,
            "name": "设备管理",
            "path": "/",
            "perms": null,
            "type": null,
            "children": [{
                "menuId": 29,
                "parentId": 7,
                "parentName": null,
                "name": "设备管理",
                "path": "/equipManage",
                "perms": null,
                "type": null,
                "children": [{
                    "menuId": 30,
                    "parentId": 29,
                    "parentName": null,
                    "name": "新增设备",
                    "path": "",
                    "perms": null,
                    "type": null,
                    "children": null
                }, {
                    "menuId": 31,
                    "parentId": 29,
                    "parentName": null,
                    "name": "投放设备",
                    "path": "",
                    "perms": null,
                    "type": null,
                    "children": null
                }, {
                    "menuId": 32,
                    "parentId": 29,
                    "parentName": null,
                    "name": "查看设备",
                    "path": "",
                    "perms": null,
                    "type": null,
                    "children": null
                }]
            }, {
                "menuId": 33,
                "parentId": 7,
                "parentName": null,
                "name": "设备状态",
                "path": "/equipStatus",
                "perms": null,
                "type": null,
                "children": null
            }]
        }, {
            "menuId": 8,
            "parentId": 1,
            "parentName": null,
            "name": "策略管理",
            "path": "/",
            "perms": null,
            "type": null,
            "children": [{
                "menuId": 35,
                "parentId": 8,
                "parentName": null,
                "name": "货道策略",
                "path": "/cargoLane",
                "perms": null,
                "type": null,
                "children": [{
                    "menuId": 36,
                    "parentId": 35,
                    "parentName": null,
                    "name": "货道配置",
                    "path": "/cargoLane",
                    "perms": null,
                    "type": null,
                    "children": [{
                        "menuId": 37,
                        "parentId": 36,
                        "parentName": null,
                        "name": "新建策略",
                        "path": "",
                        "perms": null,
                        "type": null,
                        "children": null
                    }]
                }]
            }, {
                "menuId": 38,
                "parentId": 8,
                "parentName": null,
                "name": "皮肤策略",
                "path": "/skin",
                "perms": null,
                "type": null,
                "children": null
            }]
        }, {
            "menuId": 9,
            "parentId": 1,
            "parentName": null,
            "name": "广告管理",
            "path": "/video",
            "perms": null,
            "type": null,
            "children": [{
                "menuId": 39,
                "parentId": 9,
                "parentName": null,
                "name": "广告管理",
                "path": "/video",
                "perms": null,
                "type": null,
                "children": [{
                    "menuId": 40,
                    "parentId": 39,
                    "parentName": null,
                    "name": "视频管理",
                    "path": "/video",
                    "perms": null,
                    "type": null,
                    "children": [{
                        "menuId": 42,
                        "parentId": 40,
                        "parentName": null,
                        "name": "新增视频",
                        "path": "",
                        "perms": null,
                        "type": null,
                        "children": null
                    }]
                }, {
                    "menuId": 41,
                    "parentId": 39,
                    "parentName": null,
                    "name": "图片管理",
                    "path": "/picture",
                    "perms": null,
                    "type": null,
                    "children": [{
                        "menuId": 43,
                        "parentId": 41,
                        "parentName": null,
                        "name": "新增图片",
                        "path": "",
                        "perms": null,
                        "type": null,
                        "children": null
                    }]
                }]
            }]
        }, {
            "menuId": 10,
            "parentId": 1,
            "parentName": null,
            "name": "库存管理",
            "path": "/stock",
            "perms": null,
            "type": null,
            "children": [{
                "menuId": 45,
                "parentId": 10,
                "parentName": null,
                "name": "库存管理",
                "path": "/stock",
                "perms": null,
                "type": null,
                "children": null
            }]
        }]

回答:

设置两个管理模块,一个是管理你的导航菜单,包括你的操作按钮,就是请求接口的所有按钮,另一个是管理你的角色,设置权限管理按钮,打开后展示的是你所有的导航菜单,然后选择 你要赋权的节点,当设置的用户登录的时候,从后台获取当前角色的所有节点,然后写一个全局的公共方法,验证当前按钮的节点是否存在于角色的节点数组中,如果是返回true,否则false,同时后台验证请求的接口是否存在节点中
导航菜单管理
导航菜单管理
用户组管理
用户组管理
用户权限分配
用户权限分配
节点验证
节点验证
节点判断
节点判断

回答:

后端根据登陆的角色返回导航菜单和权限字段,前端直接渲染导航菜单,判断有无权限字段来展示按钮

回答:

如果只是简单的能否看到就可以根据登录返回的权限字段进行隐藏显示。更严谨一点就可以根据权限字段隐藏显示并且在操作的时候进行权限判断(防止f12)。更保险的是后台也控制一下权限操作

回答:

按钮处理:保证页面上的按钮或者任何元素有唯一的key,命名规范就行 e.g. moudle_action_other
然后利用指令就可以处理。思路:后台所返回的菜单数据(包括按钮),应该是树结构,利用Map,转成一维数组:[‘user.list’,’user.detail’,’user.list.add.btn’,…]
然后指令中处理的逻辑就很简单了。

/**
 * 获取菜单、按钮等元素的key
 * @param menus 菜单树结构
 * @param data 引用的Map
 * @return ['user.list','user.detail','user.list.add.btn',...]
 */
export const loopForKeys = (menus, data) => {
    Array.from(menus || []).forEach(menu => {
        data.set(menu.name,
            {
                title: menu.title,
                id: menu.id,
                type: menu.type,
                name: menu.name
            });
        if (menu.subset && menu.subset.length) {
            loopForKeys(menu.subset, data);
        }
    });
};
// 指令
// 是否包含
const has = (source, modifiers) => {
    let key = Object.keys(modifiers || {}).reduce(
        (pre, next) => `${pre}.${next}`
    );
    return Array.from(source || []).indexOf(key) === -1;
};

// 是否显示
const isShow = (el, value, modifiers) => {
    isHide(el, has(value, modifiers));
};

// value 就是 store中存储的菜单树结构 -> 转成后的一维数组

export const hasAuth = {
    bind(el, { value, modifiers }) {
        isShow(el, value, modifiers);
    },
    update(el, { value, modifiers }) {
        isShow(el, value, modifiers);
    },
};

菜单和路由的处理:API 根据用户返回所对应的导航菜单,前端直接渲染就行了。不同的业务有自己的路由,思路就是动态添加路由 就行了,下面是代码可以参考。会出现的问题就是,手动浏览器输入未授权的URL,此时在router的钩子函数处理一下就行了,思路和按钮的一样,既然有了所有后端所返回的路由,再加上本地一些不需要权限控制的路由,组装之后,也可以获取到所有路由的key集合,然后查找一下就行。代码就不贴了

 getMenuByUserId().then(res => {
        // 仅设置为导航菜单
        commit(SYSTEM_SET_MENUS, res.data.records);

        let childrenRouter;

        switch (user.role_type) {
            // 管理员 所有页面
            case ROLE_OF_TYPE.PARK_MANAGER:
                childrenRouter = NormalAdminAllRouter;
                break;
            // 普通用户 所有页面
            case ROLE_OF_TYPE.NORMAL_SEND:
                childrenRouter = NormalRouter.concat(NotAuthRouter);
                break;
            // 前台 所有页面
            case ROLE_OF_TYPE.RECEPTION_SEND:
                childrenRouter = ReceptionRouter.concat(ReceptionNotAuthRouter);
                break;
        }

        // 添加全路由
        router.children = childrenRouter;


        // 设置默认路由
        router.redirect = {name: getDefaultRouter(res.data.records)};


        // 组装好的全路由
        resolve([router]);

                        }).catch(err => rej(err));

路由钩子函数过滤

export default $router => {
    $router.beforeEach((to, from, next) => {
        // 未登录
        if (!isLogin() && to.name !== LoginRouter.name) {
            next({name: LoginRouter.name});
            return;
        }

        if (isLogin()) {
            const $store = $router.app.$store;
            // 可以在store中把用户信息,可访问的菜单 缓存在内存中,这样就避免路由跳转重复请求的问题了
            $store.dispatch(ACTIONS.USER.GET_INFO).then(user => {
                $store.dispatch(ACTIONS.SYSTEM.GET_USER_MENU, user).then(router => {

                    // 添加各个角色对应路由
                    if (!$store.state.system.isAppendRouter) {
                        $router.addRoutes(router);
                        $store.commit(SYSTEM_IS_APPEND_ROUTER, true);
                    }

                    next();

                });
            });
        }

        next();
    });
};

回答:

我现在也在写这个权限需求,可以参考vue-element-admin这个项目,楼主现在解决了这个权限问题吗?

暂无评论

发表评论

您的电子邮箱地址不会被公开。 必填项已用*标注