2023年2月

在前面随笔介绍了ABP+Vue前后端的整合处理,包括介绍了ABP的后端设计,以及前端对ABP接口API的ES6的封装,通过JS的继承类处理,极大减少了重复臃肿的代码,可以简化对后端API接口的封装,而且前端使用Element组件,很好展示API获得的数据,通过在界面中展示树状列表,以及表格列表数据,可以构建一个很好的列表展示界面,而常规的界面,通过也包括了新增、编辑、查看等展示场景,一般我们通过对话框的方式进行展示处理。本篇随笔以权限管理模块中的用户管理为媒介,进行相关功能的介绍和界面设计的处理。

1、权限管理模块的设计

我们知道,权限管理一般都会涉及到用户、组织机构、角色,以及权限功能等方面的内容,ABP框架的基础内容也是涉及到这几方面的内容,其中它们之间的关系基本上是多对多的关系,它们的关系如下所示。

权限模块里面包含的一些主对象表和中间表,中间表主要用来存储两个对象之间的多对多关系,如角色包含多个用户,用户属于多个机构,机构包含多个角色等等。

结合ABP后端提供的接口,Vue前端我们要实现基础的用户、组织机构、角色、功能权限等内容的管理,以及维护它们之间的关系。Vue前端对于权限管理模块的菜单列表如下所示。

上图权限管理模块中,包括用户管理、机构管理、角色管理、菜单管理、功能管理、审计日志、登录日志等内容模块的管理。

其中用户管理模块,主要用来展示用户信息列表,以及查看对应用户权限、维护密码等处理。

用户列表界面如下所示,包括对应条件的查询和列表展示、以及查看、添加、编辑、删除、重置密码等功能入口。

用户信息查看界面如下所示

主要展示用户基础信息,和所属的关系信息,其中权限部分列出对应用户包含的功能点,用于界面按钮等方面的控制处理。

用户添加界面,则主要用来处理录入用户基础信息部分即可,如下界面所示。

用户信息录入,对用户基础表单数据进行校验,符合格式要求才能录入。

用户编辑界面,基本上和上面的类似了,不在赘述。

另外,删除用户或者重置密码,一般需对确认后再行操作,弹出一个对话框用户确认再继续。

ABP+Vue的框架参考的是已完成的ABP+Winform的功能界面进行开发,具体也可以了解下Winform版本框架《
ABP开发框架前后端开发系列---(14)基于Winform的ABP快速开发框架

2、用户管理界面功能

以上我们介绍了权限管理模块涉及的内容和关系,并着重介绍了用户管理界面中的内容展示,下面介绍在Element中如何实现对上面界面的处理的。

首先我们需要根据ABP后端的接口进行前端JS端的类的封装处理,其中前面说过,常规的Get/GetAll/Create/Update/Delete/Count等接口,我们放在BaseApi基类里面定义,其他子类继承它即可。

权限模块我们涉及到的用户管理、机构管理、角色管理、菜单管理、功能管理、审计日志、登录日志等业务类,那么这些类继承BaseApi,就会具有相关的接口了,如下所示继承关系。

我们这里以UserAPI的JS类定义介绍,如下所示。

我们以其中一个接口为例进行介绍实现代码,可以看到主要就是简单封装的调用即可。

  GetGrantedFunctionsByUser(id) { //获取用户权限列表
    returnrequest({
url:
this.baseurl + 'GetGrantedFunctionsByUser',
method:
'get',
params: { id }
})
}

有了这些业务类的准备,那么我们和后端ABP的API接口对接,就很容易了,如下图所示。

剩下的就是对Vue + Element前端的界面处理事情了。

我们先来看看查询的处理,常规的查询涉及日期区间的查询处理,这里我们用一个一个查询日期的处理操作,如下图所示。

表单的界面代码如下所示

    <el-formref="searchForm":model="searchForm"label-width="80":inline="true">
      <el-form-itemlabel="创建时间">
        <el-date-pickerv-model="searchForm.creationTime"type="daterange"align="right"unlink-panels
range-separator
="至"start-placeholder="开始日期"end-placeholder="结束日期":picker-options="pickerOptions" /> </el-form-item> <el-form-itemlabel="用户名"prop="UserName"> <el-inputv-model="searchForm.UserName" /> </el-form-item> <el-form-itemlabel="手机"prop="PhoneNumber"> <el-inputv-model="searchForm.PhoneNumber" /> </el-form-item> </el-form>

其中定义了一个pickerOptions 属性,用于快速选择日期的,在data里面增加一个这样的属性即可。

pickerOptions: {
shortcuts: [{
text:
'最近一周',
onClick(picker) {
const end
= newDate();
const start
= newDate();
start.setTime(start.getTime()
- 3600 * 1000 * 24 * 7);
picker.$emit(
'pick', [start, end]);
}
}, {
text:
'最近一个月',
onClick(picker) {
const end
= newDate();
const start
= newDate();
start.setTime(start.getTime()
- 3600 * 1000 * 24 * 30);
picker.$emit(
'pick', [start, end]);
}
}, {
text:
'最近三个月',
onClick(picker) {
const end
= newDate();
const start
= newDate();
start.setTime(start.getTime()
- 3600 * 1000 * 24 * 90);
picker.$emit(
'pick', [start, end]);
}
}]
},

在页面里面,我们定义了一些分页查询的处理条件和对象,如下所示。

查询表单则定义一个单独的表单对象,如下代码所示

      searchForm: { //查询表单
        UserName: '',
PhoneNumber:
'',
creationTime:
''},

页面加载准备好,我们就调用获取列表的数据即可。

  created() { //页面加载后,加载列表数据
    this.getlist()
},

获取列表的处理操作如下代码所示,主要就是准备构建好对应的查询参数,然后调用UserApi类的接口查询列表即可。

    getlist() { //列表数据获取
      var CreationTimeStart = ''
      if (this.searchForm.creationTime && this.searchForm.creationTime.length > 0) {
CreationTimeStart
= this.parseTime(this.searchForm.creationTime[0], '{y}-{m}-{d}')
}
var CreationTimeEnd = '' if (this.searchForm.creationTime && this.searchForm.creationTime.length > 1) {
CreationTimeEnd
= this.parseTime(this.searchForm.creationTime[1], '{y}-{m}-{d}')
}
var param = { //构造常规的分页查询条件 SkipCount: (this.pageinfo.pageindex - 1) * this.pageinfo.pagesize,
MaxResultCount:
this.pageinfo.pagesize,//过滤条件 UserName: this.searchForm.UserName,
PhoneNumber:
this.searchForm.PhoneNumber,
CreationTimeStart: CreationTimeStart,
CreationTimeEnd: CreationTimeEnd
};
//获取列表,绑定到模型上,并修改分页数量 this.listLoading = trueuser.GetAll(param).then(data=>{this.list =data.result.itemsthis.pageinfo.total =data.result.totalCountthis.listLoading = false})
},
search() {
//查询列表处理 this.pageinfo.pageindex = 1;//重置为第一页= this.getlist()
},

通过列表的查询操作,我们就可以把数据获取到,界面就会得到及时的更新显示了

      //获取列表,绑定到模型上,并修改分页数量
      this.listLoading = trueuser.GetAll(param).then(data=>{this.list =data.result.itemsthis.pageinfo.total =data.result.totalCountthis.listLoading = false})

而列表主要就是在界面使用el-table组件进行展示的了,如下图所示代码。

el-table绑定了对应的数据,并设置好显示的格式以及选择操作事件、行双击事件等操作。

而el-table里面的显示的列,需要根据我们返回数据的属性名称进行显示,如下代码所示。

而如果我们需要对属性进行特殊的展示,我们就需要使用v-if条件或者过滤器进行处理了。如下是根据不同内容,构建标签显示内容。

      <el-table-columnalign="center"label="账号激活"width="80">
        <templateslot-scope="scope">
          <el-tagv-if="scope.row.isActive === true"type="success"effect="dark">已激活</el-tag>
          <el-tagv-else type="danger"effect="dark">未激活</el-tag>
        </template>
      </el-table-column>

而对于时间,我们则可以使用格式化函数或者过滤器规范显示的格式内容。

<el-table-columnalign="center"label="创建时间"width="120"prop="creationTime":formatter="dateFormat" />

其中 :formatter="dateFormat"  指定了对应的格式化处理函数。

dateFormat(row, column, cellValue) {//this.parseTime是在main.js中的全局挂载函数
      return cellValue ? this.parseTime(cellValue, '{y}-{m}-{d}') : '' //完整格式:{y}-{m}-{d} {h}-{i}-{s}
},
timeFormat(row, column, cellValue) {
//this.parseTime是在main.js中的全局挂载函数 return cellValue ? this.parseTime(cellValue, '{y}-{m}-{d} {h}:{i}:{s}') : '' //完整格式:{y}-{m}-{d} {h}-{i}-{s} }

另外,操作列的代码,主要就是构建一些方法操作的入口,并传递对应的变量,如ID值即可。

      <el-table-columnalign="center"label="操作"width="190">
        <templatescope="scope">
          <el-row>
            <el-tooltipeffect="light"content="查看"placement="top-start">
              <el-buttonicon="el-icon-search"type="success"circle size="mini"@click="showView(scope.row.id)" />
            </el-tooltip>
            <el-tooltipeffect="light"content="编辑"placement="top-start">
              <el-buttonicon="el-icon-edit"type="primary"circle size="mini"@click="showEdit(scope.row.id)" />
            </el-tooltip>
            <el-tooltipeffect="light"content="删除"placement="top-start">
              <el-buttonicon="el-icon-delete"type="danger"circle size="mini"@click="showDelete(scope.row.id)" />
            </el-tooltip>
            <el-tooltipeffect="light"content="重置密码"placement="top-start">
              <el-buttonicon="el-icon-setting"type="warning"circle size="mini"@click="showSetPass(scope.row.id)" />
            </el-tooltip>
          </el-row>
        </template>
      </el-table-column>

列表的底部分页处理,也是利用对应的属性进行显示即可,并处理分页变化的事件。

    <divclass="block"style="height:70px;">
      <el-pagination:current-page="pageinfo.pageindex":page-size="pageinfo.pagesize":total="pageinfo.total":page-sizes="[10,20,30,40]"layout="total, sizes, prev, pager, next"@size-change="sizeChange"@current-change="currentChange"
      />
    </div>

最后完成列表界面代码,显示列表界面如下所示。

而对于查看、编辑、新增等对话框,一般我们需要创建对应的表单属性,用来承载对应的信息的,如我们为了查看信息的需要,创建一个viewForm的对象,如下所示。

      viewForm: { //查看表单
        id: '',
userName:
'',
surname:
'',
name:
'',
emailAddress:
'',
phoneNumber:
'',
ouNames:
''},

在查看信息对话框里面,我们展示对应的用户信息,包括基础信息和相关的关系,如下界面代码所示。

界面组件通过v-modal进行绑定对应的ViewForm属性对象即可。

最后,我们在触发showView函数里面,获取对应的用户信息,然后展示在界面上即可,showView函数代码如下所示。

    showView(id) { //显示查看对话框处理
      var param ={ id: id }
user.Get(param).then(data
=>{//console.log(data.result) Object.assign(this.viewForm, data.result);this.getOuName(id).then(result =>{this.viewForm.ouNames =result
})
})
this.getFunctionsByUser(id)this.isView = true},

查看界面效果如下所示。

在新增或者编辑处理界面中,我们修改了数据,都会提交到ABP后端进行录入或者更新,因此就涉及到数据的回写处理,然后提示客户端状态即可。

下面是保存编辑界面的内容操作。

    saveEdit() { //保存数据处理
      this.$refs['editForm'].validate(valid =>{if(valid) {//保存数据
          const form = this.editForm
user.Update(form).then(data
=>{//console.log(data) if(data.success) {//提示信息 this.msgSuccess('更新成功!')//刷新数据 this.getlist()
}
else{this.msgError('更新失败:' +data.error)
}
this.$refs['editForm'].resetFields()//重置窗口状态 this.closeDialog()
})
}
})
},

其中msgSuccess、msgError 是全局挂载的提示信息函数,在入口main.js里面统一处理,封装的函数方便在各个界面中统一处理。

以上就是关于用户管理界面的内容介绍,其中涉及到前端API类的封装处理,界面组件的使用,以及一些常规操作,希望能够带给大家一些vue+element开发界面的参考。

为了方便读者理解,我列出一下前面几篇随笔的连接,供参考:

循序渐进VUE+Element 前端应用开发(1)--- 开发环境的准备工作

循序渐进VUE+Element 前端应用开发(2)--- Vuex中的API、Store和View的使用

循序渐进VUE+Element 前端应用开发(3)--- 动态菜单和路由的关联处理

循序渐进VUE+Element 前端应用开发(4)--- 获取后端数据及产品信息页面的处理

循序渐进VUE+Element 前端应用开发(5)--- 表格列表页面的查询,列表展示和字段转义处理


循序渐进VUE+Element 前端应用开发(6)--- 常规Element 界面组件的使用

循序渐进VUE+Element 前端应用开发(7)--- 介绍一些常规的JS处理函数

循序渐进VUE+Element 前端应用开发(8)--- 树列表组件的使用


循序渐进VUE+Element 前端应用开发(9)--- 界面语言国际化的处理

循序渐进VUE+Element 前端应用开发(10)--- 基于vue-echarts处理各种图表展示

循序渐进VUE+Element 前端应用开发(11)--- 图标的维护和使用


循序渐进VUE+Element 前端应用开发(12)--- 整合ABP框架的前端登录处理


循序渐进VUE+Element 前端应用开发(13)--- 前端API接口的封装处理

循序渐进VUE+Element 前端应用开发(14)--- 根据ABP后端接口实现前端界面展示

循序渐进VUE+Element 前端应用开发(15)--- 用户管理模块的处理

循序渐进VUE+Element 前端应用开发(16)--- 组织机构和角色管理模块的处理

循序渐进VUE+Element 前端应用开发(17)--- 菜单管理

循序渐进VUE+Element 前端应用开发(18)--- 功能点管理及权限控制

VUE+Element 前端应用开发框架功能介绍

循序渐进VUE+Element 前端应用开发(19)--- 后端查询接口和Vue前端的整合

使用代码生成工具快速生成基于ABP框架的Vue+Element的前端界面

循序渐进VUE+Element 前端应用开发(20)--- 使用组件封装简化界面代码

循序渐进VUE+Element 前端应用开发(21)--- 省市区县联动处理的组件使用

循序渐进VUE+Element 前端应用开发(22)--- 简化main.js处理代码,抽取过滤器、全局界面函数、组件注册等处理逻辑到不同的文件中

循序渐进VUE+Element 前端应用开发(23)--- 基于ABP实现前后端的附件上传,图片或者附件展示管理

循序渐进VUE+Element 前端应用开发(24)--- 修改密码的前端界面和ABP后端设置处理

循序渐进VUE+Element 前端应用开发(25)--- 各种界面组件的使用(1)

循序渐进VUE+Element 前端应用开发(26)--- 各种界面组件的使用(2)

电商商品数据库的设计和功能界面的处理

循序渐进VUE+Element 前端应用开发(27)--- 数据表的动态表单设计和数据存储

循序渐进VUE+Element 前端应用开发(28)--- 附件内容的管理

循序渐进VUE+Element 前端应用开发(29)--- 高级查询条件的界面设计

部署基于.netcore5.0的ABP框架后台Api服务端,以及使用Nginx部署Vue+Element前端应用

循序渐进VUE+Element 前端应用开发(30)--- ABP后端和Vue+Element前端结合的分页排序处理

循序渐进VUE+Element 前端应用开发(31)--- 系统的日志管理,包括登录日志、接口访问日志、实体变化历史日志

循序渐进VUE+Element 前端应用开发(32)--- 手机短信动态码登陆处理

循序渐进VUE+Element 前端应用开发(33)--- 邮件参数配置和模板邮件发送处理

使用代码生成工具快速开发ABP框架项目

使用Vue-TreeSelect组件实现公司-部门-人员级联下拉列表的处理

使用Vue-TreeSelect组件的时候,用watch变量方式解决弹出编辑对话框界面无法触发更新的问题

在前面随笔《
循序渐进VUE+Element 前端应用开发(15)--- 用户管理模块的处理
》中介绍了用户管理模块的内容,包括用户列表的展示,各种查看、编辑、新增对话框的界面处理和后台数据处理操作,本篇随笔继续深化Vue + Element权限管理模块管理的内容,介绍组织机构和角色管理模块的处理,通过组织机构和角色管理模块的介绍,使得我们了解界面组件化模块的开发思路和做法,提高我们界面设计的技巧,并减少代码的复杂性,提高界面代码的可读性,同时也是利用组件的复用管理。

1、组织机构管理模块界面

组织机构管理模块界面如下所示,包括组织机构的成员管理和角色管理,在ABP基础领域里面,组织机构可以包含0到多个成员,也可以包含0到多个角色,因此界面设计如下所示。

在对象UML的图例中,应该是如下所示的效果图,组织机构包含组织成员和角色的内容。

在界面上,组织成员还需要添加成员的功能,同理角色也需要添加角色的处理,如下UML图示。

由于添加成员也是一个界面功能,一般情况下,如果我们放在一个页面里面,可能会增加代码量,增加代码维护难度和降低可读性,因此我们可以考虑把这些添加成员、添加角色的操作放在一个独立的组件模块里面进行设计,然后在主页面中引用组件即可。

组织机构添加成员的界面是弹出一个对话框,然后在其中查询选择系统用户列表,确认即可完成添加成员操作。

对于添加角色操作,也是类似的处理,把它们的逻辑和界面处理,封装为一个独立的界面组件,这个在Vue+Element是非常方便的,也是常用隐藏复杂性的做法。添加角色界面效果如下所示,弹出对话框中选择系统角色,确认添加到对应的组织机构即可。

2、角色管理界面

角色管理首先也是以列表展示系统角色的内容,如下界面所示。

其中每个角色,除了包含基本信息外,还会包含拥有的权限(功能控制点)、包含用户,以及拥有的菜单,其中权限是用来控制界面元素,如操作按钮的显示的,而拥有的菜单,则是用户以指定账号登录系统后,获得对应角色的菜单,然后构建对应的访问入口的。

角色界面模块UML类图如下所示。

那么对应界面元素上,我们就应该以不同的Tab来展示这些信息,如下所示。  其中可以看到不同的Tab显示不同的内容。

角色包含的权限如下所示

其中拥有的菜单也是一个树形列表,和权限类似,如下界面所示。

上面几个图是查看界面的内容,而添加或者编辑角色,则需要对树形列表进行勾选操作,以便为角色选择对应的权限和拥有的菜单权限。

我们以菜单权限为例,编辑角色信息的时候,对应的树形列表应该可以勾选,确认后把勾选的用户选择提交到后台保存处理。

3、界面模块化的处理

上面模块中,涉及到多个页面内容的处理,如果把所有的内容全部放在一个页面里面,页面内容和JS的逻辑代码将会比较臃肿,难以维护,增加编辑界面代码的难度。

其实界面设计,也是可以以UML的类图为规则,一个业务界面一个组件的方式来构建界面,而界面组件可以在多个地方重用,有时候可以设计不同的属性来区分即可。

我们回到组织机构里面添加成员和添加角色的操作UML图。

其中添加成员、添加角色,涉及界面的列表数据展示以及对应的添加展示操作,独立一个界面还是比较方便的,而且添加成员 ,在角色维护模块里面也需要用到,那么可以兼容两个场景来设计组件模块。

完成添加成员、添加角色的界面组件后,我们就可以在组织机构界面里面引入使用。

接着加入对应的组件集合里面即可。

然后在界面部分加入对应的组件呈现代码,如下所示。

有了这些准备,我们就可以在需要触发界面显示的时候,调用代码展示对应的对话框界面组件即可。

    addUser() { //显示添加成员对话框
      var ouid = this.searchForm.OrganizationUnitIdif (!ouid || typeof (ouid) === 'undefined') {this.msgError('请先选择组织机构!')return}this.$refs.selectuser.show()
},

addRole() {
//显示添加成员对话框 var ouid = this.searchForm.OrganizationUnitIdif (!ouid || typeof (ouid) === 'undefined') {this.msgError('请先选择组织机构!')return}this.$refs.selectrole.show()
},

对于角色模块也是类似,我们尽可能设计更多可以重用的界面模块,减少主模块页面代码,并提高组件的复用率。

之前介绍过,角色界面模块UML类图如下所示。

我们也可以依据这个来对模块的内容进行划分,不同业务设计不同的界面组件,最后整合一起使用即可。

这样我们查看角色详细信息的时候,界面代码就可以减少很多,只需要引入对应的界面组件即可,如下代码所示。

    <el-dialogtitle="查看信息":visible="isView":modal-append-to-body="false"@close="closeDialog">
      <el-col>
        <el-tabsvalue="basicPage"type="border-card">
          <el-tab-panename="basicPage"label="基本信息">
            <el-formref="viewForm":model="viewForm"label-width="120px">
              <el-form-itemlabel="角色名">
                <el-inputv-model="viewForm.name"disabled/>
              </el-form-item>
              <el-form-itemlabel="角色显示名">
                <el-inputv-model="viewForm.displayName"disabled/>
              </el-form-item>
              <el-form-itemlabel="角色描述">
                <el-inputv-model="viewForm.description"type="textarea"disabled/>
              </el-form-item>
            </el-form>
          </el-tab-pane>

          <el-tab-panename="permitPage"label="权限">
           <rolefunction ref="rolefunction" :role-id="selectRoleId" />
          </el-tab-pane>

          <el-tab-panename="userPage"label="用户">
           <roleuser ref="roleuser" :role-id="selectRoleId" :can-add="false" :can-delete="false" />
          </el-tab-pane>

          <el-tab-panename="menuPage"label="菜单">
           <rolemenu ref="rolemenu" :role-id="selectRoleId" />
          </el-tab-pane>
        </el-tabs>
      </el-col>
      <divslot="footer"class="dialog-footer">
        <el-buttontype="success"@click="closeDialog">关闭</el-button>
      </div>
    </el-dialog>

上面着重部分就是引入对应的界面组件,这样在编辑界面里面,我们依旧可以重用这部分的界面组件,界面组件的界面内容展示控制是内处理的,我们在主界面不用管理,非常方便。

角色查看详细界面效果如下所示。

角色的编辑界面代码如下所示。

    <el-dialogtitle="编辑信息":visible="isEdit":modal-append-to-body="false"@close="closeDialog">
      <el-col>
        <el-tabsvalue="basicPage2"type="border-card">
          <el-tab-panename="basicPage2"label="基本信息">
            <el-formref="editForm":rules="rules":model="editForm"label-width="120px">
              <el-form-itemlabel="角色名">
                <el-inputv-model="editForm.name" />
              </el-form-item>
              <el-form-itemlabel="角色显示名">
                <el-inputv-model="editForm.displayName" />
              </el-form-item>
              <el-form-itemlabel="角色描述">
                <el-inputv-model="editForm.description"type="textarea" />
              </el-form-item>
            </el-form>
          </el-tab-pane>
          <el-tab-panename="permitPage2"label="权限">
            <rolefunction ref="rolefunction2" :showcheck="true" :role-id="selectRoleId" />
          </el-tab-pane>

          <el-tab-panename="userPage2"label="用户">
            <roleuser ref="roleuser2" :role-id="selectRoleId" :can-add="true" :can-delete="true" />
          </el-tab-pane>

          <el-tab-panename="menuPage2"label="菜单">
            <rolemenu ref="rolemenu2" :showcheck="true" :role-id="selectRoleId" />
          </el-tab-pane>
        </el-tabs>
      </el-col>
      <divslot="footer"class="dialog-footer">
        <el-buttontype="primary"@click="saveEdit()">确定</el-button>
        <el-buttontype="success"@click="closeDialog">关闭</el-button>
      </div>
    </el-dialog>
  </div>

角色的编辑界面效果如下所示。

在界面组件模块里面,如果我们需要接受父组件或界面调用的时候,传入参数使用Props来定义即可。

而如果需要组件返回对应的内容,如勾选树列表的选项,那么我们在组件定义中设计一个函数用来返回组件的内容即可。

这样我们在父窗口或者父组件中就可以获得子组件的数据了。

通过上面的介绍,我们应该理解到,尽可能按界面展示业务逻辑来区分不同的组件模块,可以极大降低主界面的维护复杂性,而且界面组件也是内聚处理的,因此使用的时候也是非常方便。

通过设计不同的界面组件,我们可以组织起来更加强大的界面展示,而并不影响维护的比便利性,这个就是模块化处理的优势所在。

为了方便读者理解,我列出一下前面几篇随笔的连接,供参考:

循序渐进VUE+Element 前端应用开发(1)--- 开发环境的准备工作

循序渐进VUE+Element 前端应用开发(2)--- Vuex中的API、Store和View的使用

循序渐进VUE+Element 前端应用开发(3)--- 动态菜单和路由的关联处理

循序渐进VUE+Element 前端应用开发(4)--- 获取后端数据及产品信息页面的处理

循序渐进VUE+Element 前端应用开发(5)--- 表格列表页面的查询,列表展示和字段转义处理


循序渐进VUE+Element 前端应用开发(6)--- 常规Element 界面组件的使用

循序渐进VUE+Element 前端应用开发(7)--- 介绍一些常规的JS处理函数

循序渐进VUE+Element 前端应用开发(8)--- 树列表组件的使用


循序渐进VUE+Element 前端应用开发(9)--- 界面语言国际化的处理

循序渐进VUE+Element 前端应用开发(10)--- 基于vue-echarts处理各种图表展示

循序渐进VUE+Element 前端应用开发(11)--- 图标的维护和使用


循序渐进VUE+Element 前端应用开发(12)--- 整合ABP框架的前端登录处理


循序渐进VUE+Element 前端应用开发(13)--- 前端API接口的封装处理

循序渐进VUE+Element 前端应用开发(14)--- 根据ABP后端接口实现前端界面展示

循序渐进VUE+Element 前端应用开发(15)--- 用户管理模块的处理

循序渐进VUE+Element 前端应用开发(16)--- 组织机构和角色管理模块的处理

循序渐进VUE+Element 前端应用开发(17)--- 菜单管理

循序渐进VUE+Element 前端应用开发(18)--- 功能点管理及权限控制

VUE+Element 前端应用开发框架功能介绍

循序渐进VUE+Element 前端应用开发(19)--- 后端查询接口和Vue前端的整合

使用代码生成工具快速生成基于ABP框架的Vue+Element的前端界面

循序渐进VUE+Element 前端应用开发(20)--- 使用组件封装简化界面代码

循序渐进VUE+Element 前端应用开发(21)--- 省市区县联动处理的组件使用

循序渐进VUE+Element 前端应用开发(22)--- 简化main.js处理代码,抽取过滤器、全局界面函数、组件注册等处理逻辑到不同的文件中

循序渐进VUE+Element 前端应用开发(23)--- 基于ABP实现前后端的附件上传,图片或者附件展示管理

循序渐进VUE+Element 前端应用开发(24)--- 修改密码的前端界面和ABP后端设置处理

循序渐进VUE+Element 前端应用开发(25)--- 各种界面组件的使用(1)

循序渐进VUE+Element 前端应用开发(26)--- 各种界面组件的使用(2)

电商商品数据库的设计和功能界面的处理

循序渐进VUE+Element 前端应用开发(27)--- 数据表的动态表单设计和数据存储

循序渐进VUE+Element 前端应用开发(28)--- 附件内容的管理

循序渐进VUE+Element 前端应用开发(29)--- 高级查询条件的界面设计

部署基于.netcore5.0的ABP框架后台Api服务端,以及使用Nginx部署Vue+Element前端应用

循序渐进VUE+Element 前端应用开发(30)--- ABP后端和Vue+Element前端结合的分页排序处理

循序渐进VUE+Element 前端应用开发(31)--- 系统的日志管理,包括登录日志、接口访问日志、实体变化历史日志

循序渐进VUE+Element 前端应用开发(32)--- 手机短信动态码登陆处理

循序渐进VUE+Element 前端应用开发(33)--- 邮件参数配置和模板邮件发送处理

使用代码生成工具快速开发ABP框架项目

使用Vue-TreeSelect组件实现公司-部门-人员级联下拉列表的处理

使用Vue-TreeSelect组件的时候,用watch变量方式解决弹出编辑对话框界面无法触发更新的问题

在权限管理系统中,菜单也属于权限控制的一个资源,应该直接应用于角色,和权限功能点一样,属于角色控制的一环。不同角色用户,登录系统后,出现的系统菜单是不同的。在VUE+Element 前端中,我们菜单结合路由集合,实现可访问路由的过滤,也就实现了对应角色菜单的展示和可访问路由的控制,详细可以参考随笔《
循序渐进VUE+Element 前端应用开发(3)--- 动态菜单和路由的关联处理
》,本篇随笔主要介绍菜单管理模块的界面和相关的实现逻辑。

1、菜单资源及管理界面介绍

前面介绍过,权限管理一般都会涉及到用户、组织机构、角色,以及权限功能等方面的内容,ABP框架的基础内容也是涉及到这几方面的内容,其中它们之间的关系基本上是多对多的关系,它们的关系如下所示。

加入菜单资源,以及整理它们之间的关系和表的信息,整理图示如下。

结合ABP后端提供的接口,Vue前端我们要实现基础的用户、组织机构、角色、功能权限等内容的管理,以及维护它们之间的关系。Vue前端对于权限管理模块的菜单列表如下所示。

菜单列表管理界面如下图所示,主要包括树状列表展示菜单结构,以及具体的菜单列表查询处理。

菜单查看明细界面如下所示,主要就是简单展示菜单相关的属性数据。

而菜单的编辑或新增界面,需要考虑从已有菜单中选择列表,以及选择图标信息。

其中的Awesome图标,我们封装了选择图标的组件,只从Font Awesome图标中选择,毕竟自带的Element图标太少,不太满足要求。

关于Awesome图标组件的使用,可以参考下之前我写过的随笔《
循序渐进VUE+Element 前端应用开发(11)--- 图标的维护和使用
》。

其中的Web图标选择控件,是根据e-icon-picker控件进行修改,以采用Font Awesome图标集合的处理

//Vue-Awesome图标自动加入
const req = require.context('vue-awesome/icons', true, /\.js$/)
const requireAll
= requireContext =>requireContext.keys()
const re
= /\.\/(.*)\.js/const fontAwesome= requireAll(req).filter((key) =>{return key.indexOf('index.js') < 0}).map(i=>{return i.match(re)[1]
})

菜单的展示我们也根据配置,从Awesome中选择构建菜单的图标项目即可。

菜单项的组件,是在Layout/Components/Sidebar/Item.vue进行修改,以适应Awesome图标的处理

render(createElement, context) {
const { icon, title }
=context.props
const vnodes
=[]if(icon) {//vnodes.push(<svg-icon icon-class={icon} />) // 使用自定义svg图标 //vnodes.push(<i class={icon}/>) // 使用内置element图标 vnodes.push(<v-icon name={icon} scale='1.1' style='padding-right:3px'/>)//使用awesome图标
}
if(title) {
vnodes.push(
<span slot='title'>{(title)}</span>) }returnvnodes
}

通过各个地方进行修改,我们就可以使用Awesome的图标集合了。

2、菜单和路由的结合管理

在前面随笔《
循序渐进VUE+Element 前端应用开发(3)--- 动态菜单和路由的关联处理
》我介绍了用户动态配置的菜单资源,结合本系统的所有路由,实现菜单的显示外,还过滤了系统路由,实现可访问路由的管理,两者结合实现了系统有效的菜单和路由的控制。

前端通过接口动态获取菜单列表,通过菜单的名称和路由名称的对应关系,我们以菜单集合为对照,然后过滤本地所有静态路由的列表,然后获得用户可以访问的路由列表,设置动态路由给前端,从而实现了界面根据用户角色/权限的不同,而变化用户的菜单界面和可访问路由集合。

菜单路由处理的大概的操作过程如下所示

前端界面的动态菜单、本地路由、菜单导航和可访问路由的几个概念如下所示。

在前端界面处理中,我们通过Element界面组件的方式展示动态菜单信息,并结合菜单和路由的关系,实现菜单跳转到对应视图的处理过程。

因此,系统管理里面的菜单信息配置界面中,菜单的Web地址,对应的是系统静态路由的名称,如下界面所示。

之前定义系统的路由信息格式如下所示

//定义本系统的所有路由,具体路由呈现经过菜单数据过滤
export const asyncRoutes ={'dashboard': {
path:
'/dashboard',
component: Layout,
children: [{
path:
'dashboard',
name:
'dashboard',
component: ()
=> import('@/views/dashboard/index')
}]
},
'product': {
path:
'/product',
component: Layout,
children: [{
path:
'/product',
name:
'product',
component: ()
=> import('@/views/Product/index')
}]
},

..............................
//省略部分 'icon': {
path:
'/icon',
component: Layout,
children: [{
path:
'/icon',
name:
'icon',
component: ()
=> import('@/views/icons/index')
}]
},
'external-link': {
path:
'http://www.iqidi.com',
name:
'external-link'}
}

有了这些准备,我们在用户登录系统后,就从后台获取对应的菜单列表。

在系统登录处理过程中,考虑到初始化的时候,如果用户是管理员admin,并且获取用户菜单为空,可以考虑使用预设的静态菜单资源,可以让用户先配置好权限菜单。

    //系统静态菜单
    var staticmenus =await GetStaticMenus()//console.log(menus)

    //如果用户是admin 并且角色集合中没有菜单,则使用静态菜单
    var username = store.getters.name //用户名
    if (username === 'admin') {if (!menus || typeof (menus) === 'undefined' || menus.length === 0) {
menus
= staticmenus //系统管理员,初始化的时候使用静态菜单 }
}

由于之前开发了一个基于Winform的ABP前端应用,因此我们菜单为了整合两个应用,在菜单表示增加一个一个Tag标签,用来区分是Winform界面的菜单还是Web的菜单,毕竟两者菜单的处理方式是不同的。

      addForm: { //添加表单
        id: this.guid(),
pid:
'',
name:
'',
url:
'',
seq:
'001',
isTop:
false,
expand:
1,
visible:
1,
webIcon:
'',
tag:
'web'//Web专用 },

WInform客户端的菜单也是从服务器端请求数据,并动态构建的,Winform端的菜单展示效果如下所示。

为了方便读者理解,我列出一下前面几篇随笔的连接,供参考:

循序渐进VUE+Element 前端应用开发(1)--- 开发环境的准备工作

循序渐进VUE+Element 前端应用开发(2)--- Vuex中的API、Store和View的使用

循序渐进VUE+Element 前端应用开发(3)--- 动态菜单和路由的关联处理

循序渐进VUE+Element 前端应用开发(4)--- 获取后端数据及产品信息页面的处理

循序渐进VUE+Element 前端应用开发(5)--- 表格列表页面的查询,列表展示和字段转义处理


循序渐进VUE+Element 前端应用开发(6)--- 常规Element 界面组件的使用

循序渐进VUE+Element 前端应用开发(7)--- 介绍一些常规的JS处理函数

循序渐进VUE+Element 前端应用开发(8)--- 树列表组件的使用


循序渐进VUE+Element 前端应用开发(9)--- 界面语言国际化的处理

循序渐进VUE+Element 前端应用开发(10)--- 基于vue-echarts处理各种图表展示

循序渐进VUE+Element 前端应用开发(11)--- 图标的维护和使用


循序渐进VUE+Element 前端应用开发(12)--- 整合ABP框架的前端登录处理


循序渐进VUE+Element 前端应用开发(13)--- 前端API接口的封装处理

循序渐进VUE+Element 前端应用开发(14)--- 根据ABP后端接口实现前端界面展示

循序渐进VUE+Element 前端应用开发(15)--- 用户管理模块的处理

循序渐进VUE+Element 前端应用开发(16)--- 组织机构和角色管理模块的处理

循序渐进VUE+Element 前端应用开发(17)--- 菜单管理

循序渐进VUE+Element 前端应用开发(18)--- 功能点管理及权限控制

VUE+Element 前端应用开发框架功能介绍

循序渐进VUE+Element 前端应用开发(19)--- 后端查询接口和Vue前端的整合

使用代码生成工具快速生成基于ABP框架的Vue+Element的前端界面

循序渐进VUE+Element 前端应用开发(20)--- 使用组件封装简化界面代码

循序渐进VUE+Element 前端应用开发(21)--- 省市区县联动处理的组件使用

循序渐进VUE+Element 前端应用开发(22)--- 简化main.js处理代码,抽取过滤器、全局界面函数、组件注册等处理逻辑到不同的文件中

循序渐进VUE+Element 前端应用开发(23)--- 基于ABP实现前后端的附件上传,图片或者附件展示管理

循序渐进VUE+Element 前端应用开发(24)--- 修改密码的前端界面和ABP后端设置处理

循序渐进VUE+Element 前端应用开发(25)--- 各种界面组件的使用(1)

循序渐进VUE+Element 前端应用开发(26)--- 各种界面组件的使用(2)

电商商品数据库的设计和功能界面的处理

循序渐进VUE+Element 前端应用开发(27)--- 数据表的动态表单设计和数据存储

循序渐进VUE+Element 前端应用开发(28)--- 附件内容的管理

循序渐进VUE+Element 前端应用开发(29)--- 高级查询条件的界面设计

部署基于.netcore5.0的ABP框架后台Api服务端,以及使用Nginx部署Vue+Element前端应用

循序渐进VUE+Element 前端应用开发(30)--- ABP后端和Vue+Element前端结合的分页排序处理

循序渐进VUE+Element 前端应用开发(31)--- 系统的日志管理,包括登录日志、接口访问日志、实体变化历史日志

循序渐进VUE+Element 前端应用开发(32)--- 手机短信动态码登陆处理

循序渐进VUE+Element 前端应用开发(33)--- 邮件参数配置和模板邮件发送处理

使用代码生成工具快速开发ABP框架项目

使用Vue-TreeSelect组件实现公司-部门-人员级联下拉列表的处理

使用Vue-TreeSelect组件的时候,用watch变量方式解决弹出编辑对话框界面无法触发更新的问题

在一个业务管理系统中,如果我们需要实现权限控制功能,我们需要定义好对应的权限功能点,然后在界面中对界面元素的功能点进行绑定,这样就可以在后台动态分配权限进行动态控制了,一般来说,权限功能点是针对角色进行控制的,也就是简称RBAC(Role Based Access Control)。在前面随笔中,我们介绍了菜单资源,在权限管理系统中,菜单也是属于权限控制的一个资源,其也是作用于角色层面上的。本篇随笔介绍功能点管理及权限控制,功能点是作为一个业务对象数据进行管理,在角色范畴上进行分配,而在界面元素控制上,VUE+Element 前端引入Vue自定义指令Directives进行控制。

1、  权限功能点管理

我们在前面分析过一个权限系统的表和关系的说明,如下所示。

权限功能点的管理就是对TB_Function的表的管理操作,这个表是我们定义用于系统控制的功能点。

权限功能点的管理为了展示它的树状结果,包括树列表的管理和明细列表的管理,如下图所示。

功能点的查看界面如下所示,除了展示对应功能点的详细信息外,还列出这个功能点被那些角色拥有使用。

功能点的新增界面如下所示,主要就是选择父节点和录入功能点的信息即可。

而为了更加方便批量录入权限功能点,我们可以以业务表为基础进行批量录入,如下所示。

这样添加客户信息的功能点名称,会自动变为:Customer/Add,其他的类似,这样可以快速添加针对这个业务表的相关功能点。

有了这些功能点的定义,我们就可以结合角色管理进行分配给不同的角色了。如下是在角色编辑界面中,为角色分配不同的权限控制点。

2、VUE+Element 前端权限控制

前面内容介绍了权限功能点的管理,以及基于角色的权限实现分配处理,这些都为前端实现界面元素的权限控制做准备的。

首先我们需要根据ABP后端的接口进行前端JS端的类的封装处理,其中前面说过,常规的Get/GetAll/Create/Update/Delete/Count等接口,我们放在BaseApi基类里面定义,其他子类继承它即可。

权限模块我们涉及到的用户管理、机构管理、角色管理、菜单管理、功能管理、审计日志、登录日志等业务类,那么这些类继承BaseApi,就会具有相关的接口了,如下所示继承关系。

由于用户相关的菜单、权限集合是在用户范畴里面,我们可以在UserApi里面定义对应的后端接口调用。

其中 GetGrantedFunctionsByUser 方法就是获取指定用户的权限功能点集合的函数。

UserApi的类文件user.js内容如下所示。

其中 GetGrantedFunctionsByUser 方法就是获取指定用户的权限功能点集合的函数,函数代码如下所示。

  GetGrantedFunctionsByUser(id) { //获取用户权限列表
    returnrequest({
url:
this.baseurl + 'GetGrantedFunctionsByUser',
method:
'get',
params: { id }
})
}

在用户的Store/Modules/user.js里面,我们增加一个功能点的状态信息,如下所示。

然后在用户每次获取信息的时候,把它的功能点信息也存储起来,那么界面就可以根据这个存储内容进行相应的权限控制了。

在Mutation里面添加一个设置用户状态信息的函数,如下所示。

  SET_PERMITS: (state, permits) =>{
state.permits
=permits
}

这样我们在用户信息获取的getInfo函数里面,就可以顺便一起获取用户的包含的权限功能点信息集合了。

  //获取用户信息
getInfo({ commit, state }) {return new Promise((resolve, reject) =>{
user.getInfo(state.userid).then(response
=>{
const { result }
=response

....................

commit(
'SET_ROLES', { roles, roleNames })
commit(
'SET_NAME', name)
commit(
'SET_INTRODUCTION', fullName)// 获取用户权限
user.GetGrantedFunctionsByUser(state.userid).then(data => {
var list = data.result.items
if (list) {
var permits = []
list.forEach(element => {
if (element && element.name && typeof (element.name) !== 'undefined') {
permits.push(element.name.toLowerCase()) // 小写
}
});
// 设置用户功能权限点
commit('SET_PERMITS'
, permits)
}
})


resolve(result)
}).
catch(error =>{
reject(error)
})
})
},

现在前端也有这些权限功能点控制集合了,这些就是对应当前登录用户的可访问权限集合了。

接下来的就是需要根据这些权限集合,进行界面元素的控制了,如对一些操作按钮,如新增、编辑、删除、导入、导出等操作的按钮是否可以显示进行管理。

这个操作就是设计到Vue的自定义指令操作了,如不了解的自定义Directives的使用的,可以参考下官方介绍:
https://cn.vuejs.org/v2/guide/custom-directive.html

如我们定义一个v-permit 的自定义指令来处理权限功能点的绑定处理,那么界面应该如下处理。

    <el-rowstyle="float:right;padding-bottom:10px">
      <el-buttonicon="el-icon-search"type="primary"size="mini"round @click="search()">查询</el-button>
      <el-buttonicon="el-icon-refresh-left"type="warning"size="mini"round plain @click="resetSeachForm('searchForm')">重置</el-button>
      <el-buttonv-permit="['User/add']"icon="el-icon-plus"type="success"size="mini"round @click="showAdd()">添加</el-button>
      <el-buttonv-permit="['User/import']"icon="el-icon-upload2"type="warning"size="mini"round @click="showImport()">导入</el-button>
      <el-buttonv-permit="['User/export']"icon="el-icon-download"type="warning"size="mini"round @click="showImport()">导出</el-button>
    </el-row>

通过类似
v-permit="['User/add']"
的方式操作,就可以指定这个操作按钮的功能点,如果用户具有这些功能点,那么就可以使用,否则就不显示了。

我们在directive目录中定义一个permit.js的自定义指令文件,用来进行相应的处理的。

然后在index.js的发布文件里面定义装载处理逻辑,如下代码所示

import permit from './permit'const install= function(Vue) {
Vue.directive(
'permit', permit)
}
if(window.Vue) {
window[
'permit'] =permit//eslint-disable-next-line no-undef Vue.use(install)
}

permission.install
=install
export
default permission

最后,在main.js里面全局装载自定义指令的操作,如下代码所示。

//全局引入并使用权限控制点的自定义指令
import permission from './directive/permission'Vue.use(permission)

有了store模块里面的状态信息,以及自定义指令的支持,在界面上对应按钮元素上,就可以利用这些权限点进行控制操作了。

为了方便读者理解,我列出一下前面几篇随笔的连接,供参考:

循序渐进VUE+Element 前端应用开发(1)--- 开发环境的准备工作

循序渐进VUE+Element 前端应用开发(2)--- Vuex中的API、Store和View的使用

循序渐进VUE+Element 前端应用开发(3)--- 动态菜单和路由的关联处理

循序渐进VUE+Element 前端应用开发(4)--- 获取后端数据及产品信息页面的处理

循序渐进VUE+Element 前端应用开发(5)--- 表格列表页面的查询,列表展示和字段转义处理


循序渐进VUE+Element 前端应用开发(6)--- 常规Element 界面组件的使用

循序渐进VUE+Element 前端应用开发(7)--- 介绍一些常规的JS处理函数

循序渐进VUE+Element 前端应用开发(8)--- 树列表组件的使用


循序渐进VUE+Element 前端应用开发(9)--- 界面语言国际化的处理

循序渐进VUE+Element 前端应用开发(10)--- 基于vue-echarts处理各种图表展示

循序渐进VUE+Element 前端应用开发(11)--- 图标的维护和使用


循序渐进VUE+Element 前端应用开发(12)--- 整合ABP框架的前端登录处理


循序渐进VUE+Element 前端应用开发(13)--- 前端API接口的封装处理

循序渐进VUE+Element 前端应用开发(14)--- 根据ABP后端接口实现前端界面展示

循序渐进VUE+Element 前端应用开发(15)--- 用户管理模块的处理

循序渐进VUE+Element 前端应用开发(16)--- 组织机构和角色管理模块的处理

循序渐进VUE+Element 前端应用开发(17)--- 菜单管理

循序渐进VUE+Element 前端应用开发(18)--- 功能点管理及权限控制

VUE+Element 前端应用开发框架功能介绍

循序渐进VUE+Element 前端应用开发(19)--- 后端查询接口和Vue前端的整合

使用代码生成工具快速生成基于ABP框架的Vue+Element的前端界面

循序渐进VUE+Element 前端应用开发(20)--- 使用组件封装简化界面代码

循序渐进VUE+Element 前端应用开发(21)--- 省市区县联动处理的组件使用

循序渐进VUE+Element 前端应用开发(22)--- 简化main.js处理代码,抽取过滤器、全局界面函数、组件注册等处理逻辑到不同的文件中

循序渐进VUE+Element 前端应用开发(23)--- 基于ABP实现前后端的附件上传,图片或者附件展示管理

循序渐进VUE+Element 前端应用开发(24)--- 修改密码的前端界面和ABP后端设置处理

循序渐进VUE+Element 前端应用开发(25)--- 各种界面组件的使用(1)

循序渐进VUE+Element 前端应用开发(26)--- 各种界面组件的使用(2)

电商商品数据库的设计和功能界面的处理

循序渐进VUE+Element 前端应用开发(27)--- 数据表的动态表单设计和数据存储

循序渐进VUE+Element 前端应用开发(28)--- 附件内容的管理

循序渐进VUE+Element 前端应用开发(29)--- 高级查询条件的界面设计

部署基于.netcore5.0的ABP框架后台Api服务端,以及使用Nginx部署Vue+Element前端应用

循序渐进VUE+Element 前端应用开发(30)--- ABP后端和Vue+Element前端结合的分页排序处理

循序渐进VUE+Element 前端应用开发(31)--- 系统的日志管理,包括登录日志、接口访问日志、实体变化历史日志

循序渐进VUE+Element 前端应用开发(32)--- 手机短信动态码登陆处理

循序渐进VUE+Element 前端应用开发(33)--- 邮件参数配置和模板邮件发送处理

使用代码生成工具快速开发ABP框架项目

使用Vue-TreeSelect组件实现公司-部门-人员级联下拉列表的处理

使用Vue-TreeSelect组件的时候,用watch变量方式解决弹出编辑对话框界面无法触发更新的问题

前面介绍了很多ABP系列的文章《
ABP框架使用
》,一步一步的把我们日常开发中涉及到的Web API服务构建、登录日志和操作审计日志、字典管理模块、省份城市的信息维护、权限管理模块中的组织机构、用户、角色、权限、菜单等内容,以及配置管理模块,界面的高级查询处理等内容,并根据我们在Winform领域多年的开发经验,完成了系统功能在Winform界面下的实现,并利用工具实现快速的Winform界面生成工作;而在循序渐进VUE+Element 前端应用开发文章《
循序渐进VUE+Element
》中,则介绍了结合ABP+Vue+Element来构建BS的前端解决方案,通过Vue+Element实现的前端界面展示,界面美观大方;而且业务内容以模块化组装的Web界面,非常利于大型复杂系统的开发,极大提供了效率。

1、ABP框架背景知识介绍

ABP
是ASP.NET Boilerplate的简称,ABP是一个
开源
且文档友好的
应用程序框架
。ABP不仅仅是一个框架,它还提供了一个
最徍实践
的基于
领域驱动设计(DDD)
的体系结构模型。学习使用ABP框架也有一段时间了,一直想全面了解下这个框架的整个来龙去脉,并把想把它使用历程整理成一个系列出来,不过一直没有下笔来写这篇文章的开篇,就是希望能够深入了解,再深入了解一些,希望自己能够理解透彻一些,不能误人子弟,也不想和网上千篇一律的翻译官网的内容,官网的英文介绍也已经很详细了,于是我觉得还是以实际使用的过程进行一定的整理会更好。

初次了解ABP框架,对它还是非常惊艳的,它基本上是.NET 领域架构的集大成者,几乎囊括了我们.NET领域排的上名的各种技术应用,而且它本身可以支持.net framework和.net core两种技术流派,对它的介绍也是非常感兴趣。

1)ABP框架的特点

我们来大概了解下ABP框架涉及到的内容。

  • 依赖注入
    ,这个部分使用 Castle windsor (依赖注入容器)来实现依赖注入,这个也是我们经常使用IOC来处理的方式;
  • Repository仓储模式
    ,已实现了Entity Framework、NHibernate、MangoDB、内存数据库等,仓储模式可以快速实现对数据接口的调用;
  • 身份验证与授权管理
    ,可以使用声明特性的方式对用户是否登录,或者接口的权限进行验证,可以通过一个很细粒度的方式,对各个接口的调用权限进行设置;
  • 数据有效性验证
    ,ABP自动对接口的输入参数对象进行非空判断,并且可以根据属性的申请信息对属性的有效性进行校验;
  • 审计日志记录
    ,也就是记录我们对每个接口的调用记录,以及对记录的创建、修改、删除人员进行记录等处理;
  • Unit Of Work工作单元模式
    ,为应用层和仓储层的方法自动实现数据库事务,默认所有应用服务层的接口,都是以工作单元方式运行,即使它们调用了不同的存储对象处理,都是处于一个事务的逻辑里面;
  • 异常处理
    ,ABP框架提供了一整套比较完善的流程处理操作,可以很方便的对异常进行进行记录和传递;
  • 日志记录
    ,我么可以利用Log4Net进行常规的日志记录,方便我们跟踪程序处理信息和错误信息;
  • 多语言/本地化支持
    ,ABP框架对多语言的处理也是比较友好的,提供了对XML、JSON语言信息的配置处理;
  • Auto Mapping自动映射
    ,这个是ABP的很重要的对象隔离概念,通过使用AutoMaper来实现域对象和DTO对象的属性映射,可以隔离两者的逻辑关系,但是又能轻松实现属性信息的赋值;
  • 动态Web API层
    ,利用这个动态处理,可以把Application Service 直接发布为Web API层,而不需要在累赘的为每个业务对象手工创建一个Web API的控制器,非常方便;
  • 动态JavaScript的AJax代理处理
    ,可以自动创建Javascript 的代理层来更方便使用Web Api,这个在Web层使用。

除了这些重要特性外,ABP框架还有很多一些特别的功能或者概念。

  • 多租户支持(每个租户的数据自动隔离,业务模块开发者不需要在保存和查询数据时写相应代码;
  • 软删除支持(继承相应的基类或实现相应接口,会自动实现软删除)
  • 系统设置存取管理(系统级、租户级、用户级,作用范围自动管理)
  • EventBus实现领域事件(Domain Events)
  • 模块以及模块的依赖关系实现插件化的模块处理等等

ABP框架主要还是基于领域驱动的理念来构建整个架构的,其中领域驱动包含的概念有 域对象Entities、仓储对象Repositories、域服务接口层Domain Services、域事件Domain Events、应用服务接口Application Services、数据传输对象DTOs等。

ABP官方网站:http://www.aspnetboilerplate.com,从里面可以查看很详细的案例和文档说明,可以根据需要下载不同类型的基础框架。

ABP GitHub源码地址:https://github.com/aspnetboilerplate,可以下载整个基础的框架内容,以及相关的样板案例代码。

基于ABP框架基础上,我们整理完善了整个权限体系,以及基于这个基础上进行的业务系统快速开发,我们整理后的ABP快速开发框架的架构图示,如下图所示(以字典模块为例说明)

以上是后端API的框架架构,引入了前后端分离的Vue + Element 作为前端技术路线,那么前后端的边界则非常清晰,前端可以在通过网络获取对应的JSON就可以构建前端的应用了。

在前端处理中,主要就是利用Vuex模式中的Store对象里实现对Action和Mutation的请求处理,获取数据后,实现对State状态中的数据进行更新。如果仅仅是当前页面的数据处理,甚至可以不需要存储State信息,而直接通过前端封装的API类获取到返回的数据,直接更新到界面视图上即可。

Vue + Element前端项目的视图、Store模块、API模块、Web API之间关系如下所示。

前端根据ABP后端的接口进行前端JS端的类的封装处理,引入了ES6类的概念实现业务基类接口的统一封装,简化代码。

权限模块我们涉及到的用户管理、机构管理、角色管理、菜单管理、功能管理、审计日志、登录日志等业务类,那么这些类继承BaseApi,就会具有相关的接口了,如下所示继承关系。

2、基于Vue + Element前端ABP框架功能介绍

1)登录界面

系统登录界面效果如下所示。

或者

其中里面的文本内容,我们都是以国际化处理内容。

2)主体框架界面

主体框架界面采用的是基于后台配置的菜单动态生成,左侧是菜单,右边顶部是特定导航条和内容区。

首页内容区包括了一些常规的统计展示信息和各种图表综合展示内容。

我们来看看图表展示的效果图,其中柱状图效果如下所示。

饼状图效果如下所示。

曲线图效果如下所示。

其他类型,极坐标和散点图形

或者曲线和柱状图组合的图形

其中顶部导航条,提供查询、全屏切换、修改布局大小、多语言选择菜单、头像及快捷菜单处理。

3)用户管理界面

用户列表包括分页查询及列表展示、以及可以利用按钮进行新增、编辑、查看用户记录,或者对指定用户进行重置密码操作。

我们把常规的列表界面,新增、编辑、查看、导入等界面放在一起,除了列表页面,其他内容以弹出层对话框的方式进行处理,如下界面示意所示。

用户编辑界面如下所示。

当然可以查看这个用户本身拥有的权限功能点和拥有的菜单,如下界面所示。

4)组织机构管理

组织机构主要就是一个层级的对象关系,一般包含但不限于公司、部门、工作组等的定义,其中组织机构包含用户成员和角色成员的关系,如下界面所示。

组织机构可以修改机构名称和对应的父类节点,如下界面所示。

组织机构包含的成员可以添加多个人员记录,其中可以对组织成员列表进行添加、删除的操作。。

单击机构列表界面中组织成员部分的【添加成员】按钮,弹出对话框选择添加组织成员。

组织机构中角色列表界面如下所示,其中可以对角色列表进行添加、删除的操作。

单击机构列表界面中角色部分的【添加角色】按钮,弹出对话框选择添加角色。

5)角色管理

角色信息没有层级关系,可以通过列表展示。

其中角色包含权限分配、角色成员和拥有菜单的维护,如下是角色编辑界面,包含角色基本信息、拥有权限、包含成员、拥有菜单的管理等。菜单对于角色来说,应该是一种界面资源,可以通过配置进行管理对应角色用户的菜单。

编辑界面如下所示。

角色的权限包含系统可以用的权限,并可以勾选为角色设置所需的功能点,如下界面所示。

用户成员则和机构的用户管理一样,可以指定多个用户,这里不再赘述。

而菜单对于角色来说,应该是一种界面资源,可以通过配置进行管理对应角色用户的菜单,如下界面所示。

通过配置好角色包含的菜单,用户登录系统后,系统根据当前用户角色具有的菜单项目,动态构建显示对应的列表菜单及筛选可用路由列表。

6)功能管理

严格来说,ABP框架并没有统一管理好权限功能点的,它没有任何表来存储这个功能集合,而是通过派生AuthorizationProvider的子类来定义权限功能点

我在这个基础上引入了一个权限功能的表用来存储功能点的,然后提供管理界面来动态维护这些功能点。如下界面所示。

我们刚才在角色里面看到可以分配的权限内容,就是基于这个权限表的信息展示。

这样我们可以动态添加或者批量添加所需要的功能点,并且和整个权限管理模块串联起来,形成一个完整的控制体系。

另外我们还可以通过左侧树列表的按钮管理列表,可以添加、编辑、删除或级联删除对应的节点及其下面所有子节点。

系统登录后,客户端自动获取对应用户的角色功能点,然后我们每次打开一个新的业务窗体,客户端会进行界面的权限逻辑控制,如果没有权限的,那么不可以访问操作,如下是禁止了产品信息的导入、导出、新增、编辑等操作功能,如下界面所示产品界面被动态取消相关权限后,界面禁止了某些操作功能。

7)菜单管理

系统主界面的开发,基本上都是标准的界面,在系统左侧放置系统菜单,右侧中间区域则放置列表展示内容,但是在系统菜单比较多的时候,就需要把菜单分为几级处理。系统菜单在左侧放置一个自定义菜单组件列表,这样通过树形列表的收缩折叠,就可以放置非常多的菜单功能了。

在ABP + Vue + Element 快速开发框架里面,我们BS前端的菜单和其CS的菜单是各自分开的,我们在后台的权限模块系统中维护菜单内容并分配给对应角色用户,在用户登录系统后,动态加载菜单展示,并通过菜单的配置信息,跳转到对应的路由上去进行页面展示处理。

菜单资源管理的列表界面界面如下所示

单击左侧树列表项目,会在右侧展示对应父节点下的菜单列表。

在右侧的列表按钮中,可以对已有的菜单进行编辑,菜单编辑界面如下所示。

我们可以通过选择图标按钮进行菜单图标的选择,如下是选择菜单图片的界面。

8)系统登录日志

登录日志,这个就是用户尝试登录的时候,留下的记录信息,其中包括用户的登录用户名,ID,IP地址、登录时间,以及登录是否成功的状态等信息。

这个登录日志,就是在系统登录尝试的时候,留下的记录,可供管理员进行跟踪了解某个账户的使用情况,也可以根据这些登录信息进行一个统计报表的分析。

查看明细界面如下所示。

9)系统审计日志

审计日志,设置我们在访问或者调用某个应用服务层接口的时候,横切面流下的一系列操作记录,其中记录我们访问的服务接口,参数,客户端IP地址,访问时间,以及异常等信息,这些操作都是在ABP系统自动记录的,如果我们需要屏蔽某些服务类或者接口,则这些就不会记录在里面,否则默认是记录的。

审计日志的明细展示界面如下所示。

10)字典管理

字典管理界面,左侧列出字典类型,并对字典类型下的字典数据进行分页展示,右侧则利用分页展示对应字典类型的字典数据,字典管理界面如下所示。

字典大类在左侧列表进行维护,可以进行新增、编辑、删除等常规操作。

而对应字典大类的新增或者编辑窗体界面如下。

批量添加字典内容的界面如下所示。

11)产品列表展示

产品列表要展示一个产品相关的内容,包括展示产品的图片,以及产品信息介绍等内容。

展示界面中的顶部,我们利用Element的界面组件定义一个走马灯的展示效果,如下所示。

产品信息的另一个列表展示界面如下所示。

产品信息的编辑界面如下所示。

产品详细说明里面,我们采用富文本编辑,这里采用了 Tinymce 第三方组件来实现编辑处理,展示效果如下所示。

产品信息查看界面,可以对图片进行预览展示操作。

12)图标管理

在VUE+Element 前端应用中,图标是必不可少点缀界面的元素,因此整合一些常用的图标是非常必要的,还好Element界面组件里面提供了很多常见的图标,不过数量不是很多,应该是300个左右吧,因此考虑扩展更多图标,我引入了
vue-awesome
组件,它利用了Font Awesome的内置图标,实现了更多图标的整合。

Element图标管理界面如下:

基于Vue-Awesome的图标管理如下所示。

其中查询提供了名称进行图标查询,以及限制一次性展示多少个,另外提供一个自定义颜色选项,从而可以改变图标的展示颜色。

为了方便读者理解,我列出一下前面几篇随笔的连接,供参考:

循序渐进VUE+Element 前端应用开发(1)--- 开发环境的准备工作

循序渐进VUE+Element 前端应用开发(2)--- Vuex中的API、Store和View的使用

循序渐进VUE+Element 前端应用开发(3)--- 动态菜单和路由的关联处理

循序渐进VUE+Element 前端应用开发(4)--- 获取后端数据及产品信息页面的处理

循序渐进VUE+Element 前端应用开发(5)--- 表格列表页面的查询,列表展示和字段转义处理


循序渐进VUE+Element 前端应用开发(6)--- 常规Element 界面组件的使用

循序渐进VUE+Element 前端应用开发(7)--- 介绍一些常规的JS处理函数

循序渐进VUE+Element 前端应用开发(8)--- 树列表组件的使用


循序渐进VUE+Element 前端应用开发(9)--- 界面语言国际化的处理

循序渐进VUE+Element 前端应用开发(10)--- 基于vue-echarts处理各种图表展示

循序渐进VUE+Element 前端应用开发(11)--- 图标的维护和使用


循序渐进VUE+Element 前端应用开发(12)--- 整合ABP框架的前端登录处理


循序渐进VUE+Element 前端应用开发(13)--- 前端API接口的封装处理

循序渐进VUE+Element 前端应用开发(14)--- 根据ABP后端接口实现前端界面展示

循序渐进VUE+Element 前端应用开发(15)--- 用户管理模块的处理

循序渐进VUE+Element 前端应用开发(16)--- 组织机构和角色管理模块的处理

循序渐进VUE+Element 前端应用开发(17)--- 菜单管理

循序渐进VUE+Element 前端应用开发(18)--- 功能点管理及权限控制

VUE+Element 前端应用开发框架功能介绍

循序渐进VUE+Element 前端应用开发(19)--- 后端查询接口和Vue前端的整合

使用代码生成工具快速生成基于ABP框架的Vue+Element的前端界面

循序渐进VUE+Element 前端应用开发(20)--- 使用组件封装简化界面代码

循序渐进VUE+Element 前端应用开发(21)--- 省市区县联动处理的组件使用

循序渐进VUE+Element 前端应用开发(22)--- 简化main.js处理代码,抽取过滤器、全局界面函数、组件注册等处理逻辑到不同的文件中

循序渐进VUE+Element 前端应用开发(23)--- 基于ABP实现前后端的附件上传,图片或者附件展示管理

循序渐进VUE+Element 前端应用开发(24)--- 修改密码的前端界面和ABP后端设置处理

循序渐进VUE+Element 前端应用开发(25)--- 各种界面组件的使用(1)

循序渐进VUE+Element 前端应用开发(26)--- 各种界面组件的使用(2)

电商商品数据库的设计和功能界面的处理

循序渐进VUE+Element 前端应用开发(27)--- 数据表的动态表单设计和数据存储

循序渐进VUE+Element 前端应用开发(28)--- 附件内容的管理

循序渐进VUE+Element 前端应用开发(29)--- 高级查询条件的界面设计

部署基于.netcore5.0的ABP框架后台Api服务端,以及使用Nginx部署Vue+Element前端应用

循序渐进VUE+Element 前端应用开发(30)--- ABP后端和Vue+Element前端结合的分页排序处理

循序渐进VUE+Element 前端应用开发(31)--- 系统的日志管理,包括登录日志、接口访问日志、实体变化历史日志

循序渐进VUE+Element 前端应用开发(32)--- 手机短信动态码登陆处理

循序渐进VUE+Element 前端应用开发(33)--- 邮件参数配置和模板邮件发送处理

使用代码生成工具快速开发ABP框架项目

使用Vue-TreeSelect组件实现公司-部门-人员级联下拉列表的处理

使用Vue-TreeSelect组件的时候,用watch变量方式解决弹出编辑对话框界面无法触发更新的问题