管理界面布局

介绍

一个网站,除了普通的展示界面以外,一般还有专门用来进行后台管理的功能。在我们这个例子中就有这样的功能,比如:

  • 用户管理
  • 博客管理
  • 链接管理

其中博客管理可能还包括:

  • 博客分类的管理
  • 博客内容的管理

等内容。所以在编写博客管理功能之前,我们先把管理的展示框架先搭起来,这样,后面的管理功能就可以直接使用这些页面 布局了。我们的管理界面主要是有:

  • 导航
  • 侧边菜单
  • 内容区

创建 admin APP

在项目目录下执行:

uliweb makeapp admin

修改 views.py

将对应的 index() 改为:

@expose('/admin')
def admin_layout():
    return {}

注意,上面的链接改为了 /admin

创建 admin_layout.html

apps/admin/templates 目录下创建 admin_layout.html,它将作为所有管理的基础模板。

其内容为:

<!doctype html>
<html>
<head>
<meta http-equiv="Content-type" content="text/html; charset=utf-8" />
<title>{{block title}}Uliweb BLog Demo Admin{{end title}}</title>
</head>
<body>

<!-- resource -->
{{link "admin_layout.css"}}
{{use "semantic"}}
<!-- end resource -->

{{block content}}

<!-- head -->
<div class="head">
    <div class="ui secondary inverted menu">
        <div class="item">Uliweb Blog Demo Admin</div>
        <a class="item" href="/">
            <i class="home icon"></i> Home
        </a>
        <div class="right menu">
          <div class="ui pointing dropdown item">
            {{if request.user:}}
                <i class="icon user"></i> {{=unicode(request.user)}}
                <i class="icon dropdown"></i>
                <div class="menu">
                  <a class="item" href="/logout"><i class="sign out icon"></i> Logout</a>
                </div>
            {{else:}}
                <a href="/login">登录</a>
            {{pass}}
          </div>
        </div>
    </div>
</div>
<!-- end head -->

<!-- container -->
<div class="container">
    <div class="side-menu">
        {{block side_menu}}
            <div class="ui vertical small menu">
              <div class="header item">
                <i class="user icon"></i>
                Communities
              </div>
              <div class="item">
                College
                <div class="menu">
                  <a class="active item">Baseball</a>
                  <a class="item">Basketball</a>
                  <a class="item">Golf</a>
                </div>
              </div>
              <a class="active item">
                Dance
              </a>
              <a class="item">
                Aerobics
              </a>
            </div>
        {{end}}
    </div>
    <div class="content">
    {{block main}}
         main
    {{end}}
    </div>
</div>
<!-- end container -->

<!-- script -->
<script>
$(function(){
    $('.head .ui.dropdown').dropdown({
        on: 'hover',
        action: 'nothing'
    });

});
</script>
<!-- end script -->

{{end}}

</body>
</html>

apps/admin/static 目录下创建 admin_layout.css,它用来存放自定义的一些CSS。

其内容为:

html, body {margin:0;background-color:white;padding:0;height:100%;}
.head {background-color:#00B5AD;color:white;margin:0em;padding:4px;}
.container {margin-left:210px;position:relative;min-height:100%;background-color:white;}
.side-menu {position:absolute; top: 5px; left:-205px;width:210px;}
.content {padding:10px;}
.content .grid {margin-left:0;margin-right:0;}
.mmGrid table {font-size:14px;}
.mmPaginator {font-size:14px;}
.mmGrid .mmg-backboard label {font-size:14px;width:120px;}
.ui.secondary.inverted.menu .active.item {
background-color: rgba(255, 255, 255, 0.3);
}
.ui.form span.field_required {font-weight:bold;color:red;font-size:1.5em;}
.ui-pnotify-text {font-size:0.6em;}

展示效果

当我们在浏览器中查看 /admin 地址时,我们可以看到以下的展示效果

上面的代码主要有几个重要的地方:

title block

{{block title}}Uliweb BLog Demo Admin{{end title}} 用来定义页面的标题。这样不同的子模板通过覆盖它,可以 在不同的页面显示不同的标题。

引用资源

...
<!-- resource -->
{{link "admin_layout.css"}}
{{use "semantic"}}
<!-- end resource -->
...

其中 {{link}} 将引用为admin界面客户化的一个css文件。这个文件放在 static 目录下。

后面的 {{use}} 将引用相应的 sementic 的资源。其中 semantic 依赖的 jquery 将会被自动引入(根据前面在 sementic/settings.ini 中的依赖配置)。

定义导航条

...
<!-- head -->
<div class="head">
    <div class="ui secondary inverted menu">
        <div class="item">Uliweb Blog Demo Admin</div>
        <a class="item" href="/">
            <i class="home icon"></i> Home
        </a>
        <div class="right menu">
          <div class="ui pointing dropdown item">
            {{if request.user:}}
                <i class="icon user"></i> {{=unicode(request.user)}}
                <i class="icon dropdown"></i>
                <div class="menu">
                  <a class="item" href="/logout"><i class="sign out icon"></i> Logout</a>
                </div>
            {{else:}}
                <a href="/login">登录</a>
            {{pass}}
          </div>
        </div>
    </div>
</div>
<!-- end head -->
...

用来定义导航条。

具体菜单的结构不再做解释了,详情参见 sementic 中关于 menu 的描述和示例。

这里用到了 {{=unicode(request.user)}} ,它用来显示对应的登录用户名。但是因为我们还没有用户登录,所以在展 示界面中它是一个 None 。那么在模板中,除了可以使用由 view 函数传递过来的一些变量,还有一些全局的变量可以使用, 如: request, settings, functions, json_dumps 等。

那么 request.user 是怎么来的?它是因为我们在 apps/settings.iniINSTALLED_APPS 添加了 uliweb.contrib.auth 这个APP后,由相应的middleware自动获得用户的信息,然后注入到 request 对象上的,所以可以直接使用。但是,当 request.user 的值为 None 是表示没有用户登录。

上面关于用户信息的显示,会根据 request.user 是否存在还决定显示 登录 还是显示已登录用户名及一个用于退出的下 拉菜单。

dropdown 菜单初始化

如果用户登录了,把鼠标移动到用户名上时,会显示一个弹出菜单,这里使用了 sementic 的下拉菜单功能,它需要初始化一下 才能生效,所以下面的代码就是初始化使用:

...
<!-- script -->
<script>
$(function(){
    $('.head .ui.dropdown').dropdown({
        on: 'hover',
        action: 'nothing'
    });

});
</script>
<!-- end script -->
...

如果用户没有登录,则下拉菜单将不会生成。

on:'hover' 表示当鼠标移上去时就显示。

内容布局

container 用来定义布局,这里只是简单地定义了两栏的布局,左侧用来后面定义侧边菜单,右侧为主要的内容展示区。

所以在 container 这个 block 下又定义了两个子 block ,它们将在子模板中被覆盖。

side_menu 定义菜单。这里弄了一个缺省的展示用的菜单结构,后面我们将根据需要按这个结构来生成菜单。

从展示效果来看,这个菜单结构还是挺复杂的,它大概可以理解为:

  • 菜单块

    • 嵌套菜单

      • 子菜单项
  • 菜单块

    • 嵌套菜单

      • 子菜单项
  • 单个菜单

菜单块主要是用来定义一组菜单。单个菜单就是独立的菜单,没有子结点。

每个菜单根据需要可以有对应的图标,以及设置激活的状态。这个示例结构中,通过对菜单项添加了 class="active" 来 设置当前活动菜单。

开始的时候为了简单,我们可以先手工定义这个菜单结构,等到后面改为使用配置的方式,用函数来自动生成菜单。

关于权限处理

其实管理界面应该都是需要用户登录的,应该根据用户的权限来显示不同的菜单,并且对操作也进行权限校验。所以象直接 就能够进入管理界面应该是不允许的,应该先登录。不过登录及用户的处理,我们放到后面去做。

如果直接使用 plugs 的layout,是可以直接使用它的用户登录和管理功能的,不过在本教程中我们将自已实现简单的用户管理 功能。