django-simpleui自定義菜單權限

效果圖↓

 需要配置↓

 index.html↓

<!DOCTYPE html>
{% load i18n static %}
{% load simpletags %}
{% load customtags %}
{% get_current_language as LANGUAGE_CODE %}{% get_current_language_bidi as LANGUAGE_BIDI %}
<!--
   The project use: django-simpleui
   source code:
   https://github.com/newpanjing/simpleui
-->
<html lang="{{ LANGUAGE_CODE|default:"en-us" }}" {% if LANGUAGE_BIDI %}dir="rtl"{% endif %}>
<head>
    <meta charset="UTF-8">
    <meta name="renderer" content="webkit">
    <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
    <meta content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=0" name="viewport"/>
    {% block title %}
        <title>{{ site_title }}</title>
    {% endblock %}

    {% block icon %}
    {% endblock %}

    {% block css %}
        {% include 'admin/includes/css-part.html' %}
        <link rel="stylesheet" href="{% static 'admin/simpleui-x/css/index.css' %}?_=3.2">
        <link rel="stylesheet" href="{% static 'admin/simpleui-x/waves/waves.min.css' %}?_=2.1">
    {% endblock %}
    {% block head %}

    {% endblock %}
</head>
<body>
<style type="text/css">
    .el-tabs__nav .el-tabs__item:nth-child(1) .el-icon-close {
        display: none;
    }

    * {
        -webkit-overflow-scrolling: touch;
    }

    [v-block] {
        display: none;
    }
</style>


{% verbatim dynamicCss %}
{% endverbatim dynamicCss %}

{% block menus %}
    {% autoescape off %}
        {% custom_menus %}
    {% endautoescape %}
{% endblock %}
<div id="main" @click="mainClick($event)" v-block>
    {% block theme_css %}
        <link v-if="theme && theme!=''" rel="stylesheet" :href="theme">

        {% if "SIMPLEUI_DEFAULT_THEME"|get_config %}
            <link v-else rel="stylesheet"
                  href="{% static 'admin/simpleui-x/theme/' %}{{ "SIMPLEUI_DEFAULT_THEME"|get_config }}">
        {% endif %}
    {% endblock %}
    <!-- mobile -->
    <el-drawer
            class="lite-menus"
            title="{{ site_header }}"
            :visible.sync="drawer"
            :show-close="false"
            size="50%"
            direction="ltr">
        <el-menu unique-opened="true" :default-active="menuActive">
            <div v-for="(item,i) in menus" :key="item">
                <el-menu-item v-if="!item.models" :index="item.eid+''" @click="openTab(item,item.eid)">
                    <i :class="item.icon"></i>
                    <span slot="title" v-text="item.name"></span>
                </el-menu-item>


                <el-submenu v-else :index="item.eid+''">
                    <template slot="title">
                        <i :class="item.icon"></i>
                        <span slot="title" v-text="item.name"></span>
                    </template>

                    <el-menu-item-group v-for="(sub,j) in item.models" :title="sub.name" :key="sub.name">
                        <el-menu-item :index="sub.eid+''" @click="openTab(sub,item.eid)">
                            <i :class="sub.icon"></i>
                            <span slot="title" v-text="sub.name"></span>
                        </el-menu-item>
                    </el-menu-item-group>
                </el-submenu>

            </div>
        </el-menu>
    </el-drawer>

    <el-container :style="{height: height+'px'}">

        <el-aside v-show="!mobile" width="auto" class="menu" {% block menu_style %}{% endblock %}>
            {% block logo %}
                <div class="logo-wrap" v-if="!fold">
                    <div class="float-wrap">
                        <div class="left">
                            {% if "SIMPLEUI_LOGO"|get_config %}
                                <img src="{{ "SIMPLEUI_LOGO"|get_config |safe }}">
                            {% else %}
                                <img src="{% static 'admin/simpleui-x/img/logo.png' %}">
                            {% endif %}
                        </div>
                        <div class="left">
                            <span>{{ site_header }}</span>
                        </div>
                    </div>
                </div>
            {% endblock %}

        <!-- menu -->
        <transition name="el-zoom-in-center">
        <multiple-menu
                :menus="menus"
                :menu-active="menuActive"
                :fold="fold"
        ></multiple-menu>
        </transition>

        </el-aside>

        <el-container>
            {% block header %}
                <el-header class="navbar" style="font-size: 12px;padding: 10px;height: auto">
                    <div class="float-wrap">
                        <div class="left">
                            <el-button v-waves circle icon="fas fa-bars"
                                       style="margin-right: 10px;border: none" @click="foldClick()"></el-button>
                            {% block breadcrumb %}
                                <el-breadcrumb v-if="!mobile" style="display: inline-block;" separator="/">
                                    {% verbatim myclode %}
                                        <el-breadcrumb-item><i :class="menus[0].icon"
                                                               :key="menus[0].name"></i>{{ menus[0].name }}
                                        </el-breadcrumb-item>
                                        <el-breadcrumb-item v-for="item in breadcrumbs"
                                                            :key="item">
                                            <span :class="getIcon(item.name,item.icon)"></span>
                                            <span v-text="item.name"></span>
                                        </el-breadcrumb-item>
                                    {% endverbatim myclode %}
                                </el-breadcrumb>
                            {% endblock %}
                        </div>

                        <div class="right">
                            <el-button icon="fas fa-font" circle v-waves @click="fontClick()"></el-button>

                            <el-button
                                    :icon="this.zoom?'fas fa-compress-arrows-alt':'fas fa-expand-arrows-alt'"
                                    @click="goZoom()" circle></el-button>
                            <el-button icon="fas fa-home" @click="goIndex('{{ 'SIMPLEUI_INDEX'|get_config }}')" circle
                                       v-waves></el-button>
                            {% verbatim mycode %}
                                <el-button @click="themeDialogVisible=true" v-waves>
                                    <i class="fas fa-palette"></i>
                                    <span v-text="getLanuage('Change theme')"></span><i
                                        class="el-icon-arrow-down el-icon--right"></i>
                                </el-button>

                            {% endverbatim mycode %}
                            <el-dropdown>
                                <el-button v-waves>
                                    <i class="fas fa-user"></i>
                                    {{ user }}<i class="el-icon-arrow-down el-icon--right"></i>
                                </el-button>

                                <el-dropdown-menu slot="dropdown">
                                    {% verbatim mycode %}
                                        <el-dropdown-item v-waves icon="far fa-edit"
                                                          @click.native="changePassword()">{{ language.change_password }}
                                        </el-dropdown-item>
                                    {% endverbatim mycode %}
                                    {% has_enable_admindoc as has_admindoc %}
                                    {% if has_admindoc %}
                                        <el-dropdown-item icon="el-icon-document"
                                                          @click.native="openTab({eid:100000,name:'{% trans 'Documentation' %}',icon:'el-icon-document',url:'{% url 'django-admindocs-docroot' %}'})"
                                                          divided>{% trans 'Documentation' %}</el-dropdown-item>
                                    {% endif %}

                                    {% verbatim mycode %}
                                        <el-dropdown-item icon="el-icon-close"
                                                          @click.native="logout()"
                                                          divided>{{ language.logout }}</el-dropdown-item>
                                    {% endverbatim mycode %}
                                </el-dropdown-menu>
                            </el-dropdown>
                        </div>
                    </div>
                </el-header>
            {% endblock %}
            <el-main>
                <el-tabs v-model="tabModel" {% block tabs_type %}type="border-card" {% endblock %} editable
                         :style="isResize?'height:100%':'height: calc(100% - 97px)'" @edit="handleTabsEdit"
                         @tab-click="tabClick">

                    <el-tab-pane v-for="(item,index) in tabs" :closable="index!=0" :label="item.name" :name="item.id"
                                 :key="item.id" lazy="true">

                        {% home_page %}
                        {% if home %}
                            <span v-if="index==0" slot="label"><i
                                    class="{{ icon }}"></i><span>{{ title }}</span>
                            </span>
                            <span v-else slot="label" @contextmenu.prevent="contextmenu(item,$event)">
                        {% else %}
                            <span slot="label" @contextmenu.prevent="contextmenu(item,$event)">
                        {% endif %}

                        {% block tab-item %}
                            <i :class="item.loading?'el-icon-loading':item.icon"></i>
                            <span v-text="item.name"></span>
                        {% endblock %}
                        </span>

                        <div v-if="index==0" style="height:100%">
                            {% block home_content %}
                                {% if home %}
                                    <iframe :src="'{{ home }}'"></iframe>
                                {% else %}
                                    {% include './home.html' %}
                                {% endif %}
                            {% endblock %}
                        </div>
                        <div v-else class="iframe-wrap">
                            <iframe :src="item.url" :id="item.id" @load="iframeLoad(item,$event)"></iframe>
                            {% if "SIMPLEUI_LOADING"|get_config != False %}
                                <div v-if="loading" class="loading" @dblclick="loading=false">
                                    <div class="center">
                                        <span class="el-icon-loading"></span>
                                        <span>loading...</span>
                                    </div>
                                </div>
                            {% endif %}

                        </div>
                    </el-tab-pane>


                </el-tabs>
            </el-main>
        </el-container>
    </el-container>

    <ul v-if="popup.show" class="el-dropdown-menu el-popper" ref="popupmenu"
        :style="{position: 'absolute',top: popup.top+'px',left: popup.left+'px'}" x-placement="top-end">
        <li v-for="(item,index) in popup.menus" tabindex="-1" class="el-dropdown-menu__item"
            @click="item.handler(popup.tab,item)"><i :class="item.icon"></i><span
                v-text="item.text"></span>
        </li>
    </ul>
    <el-dialog title="{% trans 'Change password' %}" :visible.sync="pwdDialog.show">
        <iframe frameborder="0" :src="pwdDialog.url" width="100%" height="500"></iframe>
    </el-dialog>

    {% block theme_dialog %}
        <el-dialog
                :title="getLanuage('Change theme')"
                :visible.sync="themeDialogVisible"
                :width="small?'90%':'50%'">
            {% block theme_body %}
                <div class="change-theme clearfix">
                    <div v-waves :class="{'theme-item':true,active:themeName==item.text}" v-for="(item,i) in themes"
                         :key="item.text"
                         :title="getLanuage(item.text)" @click="setTheme(item)">
                        <div class="theme-menu" :style="{background:item.menu}">
                            <div class="theme-logo" :style="{background: item.logo}"></div>
                        </div>
                        <div class="theme-top" :style="{background: item.top}"></div>
                    </div>
                </div>
            {% endblock %}
        </el-dialog>
    {% endblock %}

    {% block font_dialog %}
        <el-dialog
                :title="getLanuage('Set font size')"
                :visible.sync="fontDialogVisible"
                :width="small?'90%':'50%'">
            <el-slider v-model="fontSlider" :min="12" :max="100" show-input @change="fontSlideChange"></el-slider>
            <div style="text-align: right;padding-top: 20px">
                <el-button type="primary" @click="reset()" v-text="getLanuage('Reset')"></el-button>
            </div>
        </el-dialog>
    {% endblock %}
</div>
{% block base_script %}
    <script type="text/javascript">
        {% if home %}
            var home = {
                id: '0',
                index: '1',
                name: '{{ title }}',
                icon: '{{ icon }}',
                active: true,
                eid: '1'
            }
        {% else %}
            var home = {
                id: '0',
                index: '1',
                eid: '1',
                name: "{% trans 'Home' %}",
                icon: 'fas fa-home'
            };
        {% endif %}
        menus.unshift(home);
        window.language = {
            change_password: '{% trans 'Change password' %}',
            logout: '{% trans 'Log out' %}',
            yes: '{% trans 'Yes' %}',
            no: '{% trans 'No' %}',
            confirm: '{% trans 'Are you sure?' %}'
        }
        window.themeUrl = '{% static 'admin/simpleui-x/theme/' %}';
        window.urls = {
            changePassword: "{% url 'admin:password_change' %}",
            logout: "{% url 'admin:logout' %}"
        }
        var lanuageCode = '{% get_language %}';

        function localeError(e) {
            console.warn("Please add the {% get_language %}.js language file to the '/simpleui-x/theme' directory.")
            console.log("See simpleui i18n:https://github.com/newpanjing/simpleui/blob/master/i18n.md")
            console.log("或者加入QQ羣:786576510 (Join QQ Group.)")

        }
    </script>

    {% include 'admin/includes/js-part.html' %}

    <script type="text/javascript">
        __simpleui_version = '{% simple_version %}';
    </script>
    <script type="text/javascript"
            src="{% static 'admin/simpleui-x/automatic/dicts.js' %}?_={% get_version %}"></script>
    <script type="text/javascript"
            src="{% static 'admin/simpleui-x/automatic/segment.js' %}?_={% get_version %}"></script>
    <script type="text/javascript" src="{% static 'admin/simpleui-x/locale/en-us.js' %}?_={% get_version %}"></script>
    <script type="text/javascript"
            src="{% static 'admin/simpleui-x/locale/' %}{% get_language %}.js?_={% get_version %}"
            onerror="localeError()"></script>
    <script type="text/javascript" src="{% static 'admin/simpleui-x/js/cookie.js' %}?_={% get_version %}"></script>
    <script type="text/javascript" src="{% static 'admin/simpleui-x/theme/theme.js' %}?_={% get_version %}"></script>
    <script type="text/javascript"
            src="{% static 'admin/simpleui-x/waves/waves.min.js' %}?_={% get_version %}"></script>
    {% block index_js %}
        <script type="text/javascript" src="{% static 'admin/simpleui-x/js/menu.js' %}?_={% get_version %}"></script>
        <script type="text/javascript" src="{% static 'admin/simpleui-x/js/index.js' %}?_={% get_version %}"></script>
    {% endblock %}
    {% block autoupdate %}

    {% endblock %}
{% endblock %}
{% load_analysis %}
{% block script %}
    {#    預留腳本block 可以實現基礎該頁面,添加自定義腳本#}
{% endblock %}
</body>
</html>

customtags↓

# -*- coding: utf-8 -*-

import base64
import json
import os
import sys

from django import template
from django.core.serializers.json import DjangoJSONEncoder
from django.utils.functional import Promise

try:
    from django.utils.encoding import force_text
except:
    from django.utils.encoding import force_str as force_text

register = template.Library()

PY_VER = sys.version[0]  # 2 or 3

if PY_VER != '2':
    from importlib import reload
    from urllib.parse import parse_qsl
else:
    from urlparse import parse_qsl


class LazyEncoder(DjangoJSONEncoder):
    """
        解決json __proxy__ 問題
    """

    def default(self, obj):
        if isinstance(obj, Promise):
            return force_text(obj)
        return super(LazyEncoder, self).default(obj)


def unicode_to_str(u, encoding='utf-8'):
    if PY_VER != '2':
        return u
    return u.encode(encoding)


@register.filter
def to_str(obj):
    return str(obj)


def __get_config(name):
    from django.conf import settings
    value = os.environ.get(name, getattr(settings, name, None))

    return value

@register.filter
def get_config(key):
    return __get_config(key)


@register.simple_tag(takes_context=True)
def custom_menus(context, _get_config=None):
    data = []
    # print(context.request.user.has_perm("%s.%s" % (opts.app_label, codename))
    if not _get_config:
        _get_config = get_config

    config = _get_config('SIMPLEUI_CONFIG')
    if not config:
        config = {}

    if config.get('dynamic', False) is True:
        config = _import_reload(_get_config('DJANGO_SETTINGS_MODULE')).SIMPLEUI_CONFIG

    app_list = context.get('app_list')
    for app in app_list:
        _models = [
            {
                'name': m.get('name'),
                'icon': get_icon(m.get('object_name'), unicode_to_str(m.get('name'))),
                'url': m.get('admin_url'),
                'addUrl': m.get('add_url'),
                'breadcrumbs': [{
                    'name': app.get('name'),
                    'icon': get_icon(app.get('app_label'), app.get('name'))
                }, {
                    'name': m.get('name'),
                    'icon': get_icon(m.get('object_name'), unicode_to_str(m.get('name')))
                }]
            }
            for m in app.get('models')
        ] if app.get('models') else []

        module = {
            'name': app.get('name'),
            'icon': get_icon(app.get('app_label'), app.get('name')),
            'models': _models
        }
        data.append(module)

    # 如果有menu 就讀取,沒有就調用系統的
    key = 'system_keep'
    if config and 'menus' in config:
        if config.get(key, None):
            temp = config.get('menus')
            _temp = temp[:]
            for i in _temp:
                if 'models' not in i:
                    if context.request.user.has_perm("%s.%s" % (i.get("name"), i.get("codename"))):
                        i['breadcrumbs'] = [{
                            'name': i.get('name'),
                            'icon': i.get('icon')
                        }]
                    else:
                        temp.remove(i)
                else:
                    _i = i.get('models')[:]
                    for k in _i:
                        if context.request.user.has_perm("%s.%s" % (k.get("name"), k.get("codename"))):
                            k['breadcrumbs'] = [{
                                'name': i.get('name'),
                                'icon': i.get('icon')
                            }, {
                                'name': k.get('name'),
                                'icon': k.get('icon')
                            }]
                        else:
                            i.get("models").remove(k)
                    if not i.get("models"):
                        temp.remove(i)

            for i in temp:
                data.append(i)
        else:
            data = config.get('menus')

    # 獲取側邊欄排序, 如果設置了就按照設置的內容排序, 留空則表示默認排序以及全部顯示
    if config.get('menu_display') is not None:
        display_data = list()
        for _app in data:
            if _app['name'] not in config.get('menu_display'):
                continue
            _app['_weight'] = config.get('menu_display').index(_app['name'])
            display_data.append(_app)
        display_data.sort(key=lambda x: x['_weight'])
        data = display_data
    # 給每個菜單增加一個唯一標識,用於tab頁判斷
    eid = 1000
    handler_eid(data, eid)
    menus_string = json.dumps(data, cls=LazyEncoder)

    # 把data放入session中,其他地方可以調用
    if not isinstance(context, dict) and context.request:
        context.request.session['_menus'] = menus_string

    return '<script type="text/javascript">var menus={}</script>'.format(menus_string)


def handler_eid(data, eid):
    for i in data:
        eid += 1
        i['eid'] = eid
        if 'models' in i:
            eid = handler_eid(i.get('models'), eid)
    return eid


def get_icon(obj, name=None):
    temp = get_config_icon(name)
    if temp != '':
        return temp

    _dict = {
        'auth': 'fas fa-shield-alt',
        'User': 'far fa-user',
        'Group': 'fas fa-users-cog'
    }

    temp = _dict.get(obj)
    if not temp:
        return 'far fa-circle'

    return temp


# 從配置中讀取圖標
def get_config_icon(name):
    _config_icon = __get_config('SIMPLEUI_ICON')
    if _config_icon is None:
        return ''

    if name in _config_icon:
        return _config_icon.get(name)
    return ''


def _import_reload(_modules):
    _obj = __import__(_modules, fromlist=_modules.split('.'))
    reload(_obj)
    return _obj

index.html路徑一定要按照第三張截圖所示配置,customtags.py文件可以放在任意APP目錄下的templatetags目錄下

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章