zoukankan      html  css  js  c++  java
  • 权限组件(2):二级菜单

    二级菜单效果图

    一、把一级菜单从权限表里抽离出来,单独创建一个表

    rbac/models
    Menu

    class Menu(models.Model):
        """
        菜单表
        """
        title = models.CharField(verbose_name='一级菜单的名称', max_length=32)
        icon = models.CharField(verbose_name='图标', max_length=32, null=True, blank=True)
    
        def __str__(self):
            return self.title

    Permission

    class Permission(models.Model):
        """
        权限表
        """
        title = models.CharField(verbose_name='标题', max_length=32)
        url = models.CharField(verbose_name='含正则的URL', max_length=128)
    
        menu = models.ForeignKey(verbose_name='所属菜单', to=Menu, null=True, blank=True,
                                 help_text='null表示不是菜单,非null表示是二级菜单', on_delete=models.CASCADE
                                 )
    
        def __str__(self):
            return self.title

     

    二、修改初始化权限

    rbac/service/init_permission.py
    思路:

    1. 获取一级菜单和二级菜单的信息
    2. 找出有menu_id的菜单(可以做二级菜单的)
    3. 将一级菜单的id作为key,values还是一个字典,里面储存一级菜单的标题、图标和二级菜单。

     代码:

    from permission_learn import settings
    
    
    def init_permission(current_user, request):
        """
        用户权限的初始化
        :param current_user:  当前登录用户
        :param request:
        :return:
        """
    
        permission_menu_queryset = current_user.roles.filter(permissions__isnull=False).values(
            'permissions__id',
            'permissions__title',
            'permissions__url',
            'permissions__menu_id',  # +
            'permissions__menu__title',  # +
            'permissions__menu__icon',  # +
        ).distinct()
    
        menu_dict = {}
        permission_list = []
    
        for item in permission_menu_queryset:
            permission_list.append(item['permissions__url'])
    
            menu_id = item['permissions__menu_id']
    
            if not menu_id:
                continue
    
            second_menu = {'title': item['permissions__title'], 'url': item['permissions__url']}
    
            if menu_id in menu_dict:
                menu_dict[menu_id]['second_menu'].append(second_menu)
            else:
                menu_dict[menu_id] = {
                    'title': item['permissions__menu__title'],
                    'icon': item['permissions__menu__icon'],
                    'second_menu': [second_menu, ]
                }
    
        request.session[settings.PERMISSION_SESSION_KEY] = permission_list
        request.session[settings.MENU_SESSION_KEY] = menu_dict
    
    
    """
    客户列表    /customer/list/  1  ForeignKey -->  1 客户管理  fa-hdd-o
        添加客户    /customer/add/  null
        编辑客户    /customer/edit/(?P<cid>d+)/  null
        删除客户    /customer/del/(?P<cid>d+)/  null
    """

    三、渲染到模板

    rbac/templatetags/rbac.py

    import re
    from collections import OrderedDict
    
    from django.conf import settings
    from django.template import Library
    
    register = Library()
    @register.inclusion_tag('rbac/multi_menu.html')
    def multi_menu(request):
        menu_dict = request.session[settings.MENU_SESSION_KEY]
    
        # 对字典的key进行排序。得到的结果是只包含Key的列表,类似这样的 [1,2,3]
        key_list = sorted(menu_dict)
    
        # 空的有序字典
        ordered_dict = OrderedDict()  # 有序字典,按照我们想要的顺序展示
        current_path = request.path
        for key in key_list:
            menu = menu_dict[key]  # {'title':'客户管理','icon':'fa fa-book','second_menu':[二级菜单1,二级菜单2,...]}
            menu['class'] = 'hide'  # 隐藏二级菜单
            for second_menu in menu['second_menu']:
                regex = '^%s$' % second_menu['url']
                if re.match(regex, current_path):
                    second_menu['class'] = 'active'
                    menu['class'] = ''  # 显示点中的二级菜单
    
            ordered_dict[key] = menu
    
        context = {
            'menus': ordered_dict
        }
    
        return context

    需要注意的是对字典的key进行排序得到的结果是只包含Key的列表,menu_dict的key是menu_id,最后得到这样的 [1,2,3...]的结果

    通过templatestag渲染二级菜单到模板:rbac/templates/rbac/multi_menu.html

    <div class="multi-menu">
        {% for menu in menus.values %}
            <div class="item">
                <div class="title">
            <span class="icon-wrap">
                <i class="fa {{ menu.icon }}"></i>
            </span>
                    {{ menu.title }}
                </div>
                <div class="body {{ menu.class }}">
                    {% for second_menu in menu.second_menu%}
                        <a href="{{ second_menu.url }}" class="{{ second_menu.class }}">{{ second_menu.title }}</a>
                    {% endfor %}
                </div>
            </div>
        {% endfor %}
    </div>

    layout.html页面只需要把一级菜单的templates替换成二级菜单的就行

        -       {% menu request %}
        +       {% multi_menu request %}

    js代码:rbac/static/rbac/js/rbac.js

    $('.multi-menu .title').click(function () {
        $(this).next().toggleClass('hide');
    }); 

    toggleClass检查每个元素中指定的类。如果不存在则添加类,如果已设置则删除之。这就是所谓的切换效果。

    css代码:rbac/static/rbac/css/rbac.css

    '''
    .multi-menu .item {
    
    }
    
    .multi-menu .item > .title {
    padding: 10px 5px;
    border-bottom: 1px solid #dddddd;
    cursor: pointer;
    color: #333;
    display: block;
    background: #efefef;
    background: -webkit-gradient(linear, left bottom, left top, color-stop(0, #efefef), color-stop(1, #fafafa));
    background: -ms-linear-gradient(bottom, #efefef, #fafafa);
    background: -o-linear-gradient(bottom, #efefef, #fafafa);
    filter: progid:dximagetransform.microsoft.gradient(startColorStr='#e3e3e3', EndColorStr='#ffffff');
    -ms-filter: "progid:DXImageTransform.Microsoft.gradient(startColorStr='#fafafa',EndColorStr='#efefef')";
    box-shadow: inset 0 1px 1px white;
    }
    
    .multi-menu .item > .body {
    border-bottom: 1px solid #dddddd;
    }
    
    .multi-menu .item > .body a {
    display: block;
    padding: 5px 20px;
    text-decoration: none;
    border-left: 2px solid transparent;
    font-size: 13px;
    
    }
    
    .multi-menu .item > .body a:hover {
    border-left: 2px solid #2F72AB;
    }
    
    .multi-menu .item > .body a.active {
    border-left: 2px solid #2F72AB;
    }
    '''

    中间件不需要改动

  • 相关阅读:
    0x01 虚拟环境搭建
    python操作mysql8windows环境
    Navicat 导入sql文件执行失败问题的处理
    mysql8.0.16免安装教程
    zend studio 9.0.3 注册码
    oneplus8手机蓝牙连接tws耳机无法双击退出语音助手
    竞品分析
    源码阅读方法
    Tomcat内核1
    Asp.NetCore3.1开源项目升级为.Net6.0
  • 原文地址:https://www.cnblogs.com/lshedward/p/10494653.html
Copyright © 2011-2022 走看看