wenmo8 发布的文章

VUE+Element 前端是一个纯粹的前端处理,前面介绍了很多都是Vue+Element开发的基础,从本章随笔开始,就需要进入深水区了,需要结合ABP框架使用(如果不知道,请自行补习一下我的随笔:
ABP框架使用
),ABP框架作为后端,是一个非常不错的技术方向,但是前端再使用Asp.NET 进行开发的话,虽然会快捷一点,不过可能显得有点累赘了,因此BS的前端选项采用Vue+Element来做管理(后续可能会视情况加入Vue+AntDesign),CS前端我已经完成了使用Winform+ABP的模式了。本篇随笔主要介绍Vue+Element+ABP的整合方式,先从登录开始介绍。

1、ABP开发框架的回顾

ABP
是ASP.NET Boilerplate的简称,ABP是一个
开源
且文档友好的
应用程序框架
。ABP不仅仅是一个框架,它还提供了一个
最徍实践
的基于
领域驱动设计(DDD)
的体系结构模型。

启动Host的项目,我们可以看到Swagger的管理界面如下所示。

我们登录获得用户访问令牌token后,测试字典类型或者字典数据的接口,才能返回响应的数据。

我根据ABP后端项目之间的关系,整理了一个架构的图形。

应用服务层是整个ABP框架的灵魂所在,对内协同仓储对象实现数据的处理,对外配合Web.Core、Web.Host项目提供Web API的服务,而Web.Core、Web.Host项目几乎不需要进行修改,因此应用服务层就是一个非常关键的部分,需要考虑对用户登录的验证、接口权限的认证、以及对审计日志的记录处理,以及异常的跟踪和传递,基本上应用服务层就是一个大内总管的角色,重要性不言而喻。

对于通过Winform方式展示界面,以Web API方式和后端的ABP的Web API服务进行数据交互,是我们之前已经完成的项目,项目界面如下所示。

主体框架界面采用的是基于菜单的动态生成,以及多文档的界面布局,具有非常好的美观性和易用性。

左侧的功能树列表和顶部的菜单模块,可以根据角色拥有的权限进行动态构建,不同的角色具有不同的菜单功能点,如下是测试用户登录后具有的界面。

2、Vue+Element整合ABP框架的前端登录处理

之前我们开发完成的Vue+Element的前端项目,默认已经具有登录系统的功能,不过登录是采用mock方式进行验证并处理的,本篇随笔介绍是基于实际的ABP项目进行用户身份的登录处理,这个也是开发其他接口展示数据的开始步骤,必须通过真实的用户身份登录后台,获得对应的token令牌,才能进行下一步接口的开发工作。

例如对应登录界面上,界面效果如下所示。

在用户登录界面中,我们处理用户登录逻辑代码如下所示。

    //处理登录事件
handleLogin() {this.$refs.loginForm.validate(valid =>{if(valid) {this.loading = true
          this.$store
.dispatch(
'user/login', this.loginForm)
.then(()
=>{this.$router.push({ path: this.redirect || '/'})this.loading = false})
.
catch(() =>{this.loading = false})
}
else{
console.log(
'error submit!!')return false}
})
}

这里主要就是调用Store模块里面的用户Action处理操作。

例如对于用户store模块里面的登录Action函数如下所示。

const actions ={//user login
login({ commit }, userInfo) {
const { username, password }
=userInforeturn new Promise((resolve, reject) =>{
login({ username: username.trim(), password: password }).then(response
=>{
const { result }
= response //获取返回对象的 result var token = result.accessToken
var userId = result.userId
//记录令牌和用户Id commit('SET_TOKEN', token)
commit(
'SET_USERID', userId)//存储cookie setToken(token)
setUserId(userId)
resolve()
}).
catch(error =>{
reject(error)
})
})
},

而其中 login({ username: username.trim(), password: password }) 操作,是通过API封装处理的调用,使用前在Store模块中先引入API模块,如下所示。

import { login, logout, getInfo } from '@/api/user'

而其中 API模块代码如下所示。

export functionlogin(data) {returnrequest({
url:
'/abp/TokenAuth/Authenticate',
method:
'post',
data: {
UsernameOrEmailAddress: data.username,
password: data.password
}
})
}

这里我们用了一个/abp的前缀,用来给WebProxy的处理,实现地址的转义,从而可以实现跨站的处理,让前端调用外部地址就和调用本地地址一样,无缝对接。

我们来看看vue.config.js里面对于这个代理的转义操作代码。

而 http://localhost:21021/api 地址指向的项目,是我们本地使用ABP开发的一个后端Web API项目,我们可以通过地址
http://localhost:21021/swagger/index.html
进行接口的查看。

我们打开获取授权令牌的Authenticate接口,查看它的接口定义内容

通过标注的1,2,我们可以看到这个接口的输入参数和输出JSON信息,从而为我们封装Web API的调用提供很好的参考。

ABP框架统一返回的结果是result,这个result里面才是返回对应的接口内容,如上面的输出JSON信息里面的定义。

所以在登陆返回结果后,我们要返回它的result对象,然后在进行数据的处理。

const { result } = response //获取返回对象的 result

然后通过result来访问其他属性即可。

var token = result.accessToken //用户令牌
var userId = result.userId //用户id

用户登录成功后,并获取到对应的数据,我们就可以把必要的数据,如token和userid存储在State和Cookie里面了。

//修改State对象,记录令牌和用户Id
commit('SET_TOKEN', token)
commit(
'SET_USERID', userId)//存储cookie setToken(token)
setUserId(userId)

有了这些信息,我们就可以进一步获取用户的相关信息,如用户名称、介绍,包含角色列表和权限列表等内容了。

例如对应用户信息获取接口的ABP后端地址是
http://localhost:21021//api/services/app/User/Get

那么我们前端就需要在API模块里面构建它的访问地址(/abp/services/app/User/Get)和接口处理了。

export functiongetInfo(id) {returnrequest({
url:
'/abp/services/app/User/Get',
method:
'get',
params: {
id
}
})
}

如上所示,在Store模块里引入API模块,如下所示。

import { login, logout, getInfo } from '@/api/user'

然后在Store模块中封装一个Action用来处理用户信息的获取的。

  //获取用户信息
getInfo({ commit, state }) {return new Promise((resolve, reject) =>{
getInfo(state.userid).then(response
=>{
const { result }
=response
console.log(result)
//输出测试 if (!result) {
reject(
'Verification failed, please Login again.')
}

const { roles, roleNames, name, fullName }
=result//角色非空提醒处理 if (!roles || roles.length <= 0) {
reject(
'getInfo: roles must be a non-null array!')
}

commit(
'SET_ROLES', { roles, roleNames })
commit(
'SET_NAME', name)//commit('SET_AVATAR', avatar) //可以动态设置头像 commit('SET_INTRODUCTION', fullName)
resolve(result)
}).
catch(error =>{
reject(error)
})
})
},

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

登录后我们获取用户身份信息,在控制台中记录返回对象信息,可以供参考,如下所示

有了token信息,我们就可以继续其他接口的数据请求或者提交了,从而可以实现更多的管理功能了。

后续随笔将基于ABP接口对接的基础上进行更多界面功能的开发和整合。

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

循序渐进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 前端应用开发(12)--- 整合ABP框架的前端登录处理
》介绍了一个系统最初接触到的前端登录处理的实现,但往往对整个系统来说,一般会有很多业务对象,而每个业务对象的API接口又有很多,不过简单来说也就是常规的增删改查,以及一些自定义的接口,通用都比较有规律性。而本身我们这个VUE+Element 前端应用就是针对ABP框架的业务对象,因此前端的业务对象接口也是比较统一的,那么可以考虑在前端中对后端API接口调用进行封装,引入ES6的方式进行前端API的抽象简化。本篇随笔主要针对这个方面,介绍前端API接口的封装处理,以便简化我们大量类似的业务接口的累赘代码实现。

1、ABP框架API接口的回顾

ABP
是ASP.NET Boilerplate的简称,ABP是一个
开源
且文档友好的
应用程序框架
。ABP不仅仅是一个框架,它还提供了一个
最徍实践
的基于
领域驱动设计(DDD)
的体系结构模型。

启动Host的项目,我们可以看到Swagger的管理界面如下所示。

上图就是ABP后端框架的API接口的查看页面,从上图可以看到,一般业务对象,都有Get、GetAll、Create、Update、Delete等常见接口,由于这些接口是给前端进行调用的。

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

前面介绍了,一般前端调用,通过前端API类的封装,即可发起对后端API接口的调用,如系统登录API定义如下代码所示。

export functiongetInfo(id) {returnrequest({
url:
'/abp/services/app/User/Get',
method:
'get',
params: {
id
}
})
}

按照常规的API类的处理,我们对应的业务类,就需要定义很多这样的函数,如之前介绍产品信息处理的API接口一样。

由于常规的增删改查,都是标准的API接口,那么如果我们按照每个API类都需要重复定义这些API,显然不妥,太臃肿。

如果是常规的JS,那么就以公布函数方式定义API接口,不过我们可以引入ES6的处理方式,在JS中引入类和继承的概念进行处理相同的API接口封装。

2、基于ES6的JS业务类的封装

关于ES6,大家可以有空了解一下《
ES6 入门教程
》,可以全面了解ES6很多语法和相关概念。

不过这里只需要了解一下JS里面关于类的定义和继承的处理关系即可。

ES6 提供了更接近传统语言的写法,引入了 Class(类)这个概念,作为对象的模板。通过
class
关键字,可以定义类。

基本上,ES6 的
class
可以看作只是一个语法糖,它的绝大部分功能,ES5 都可以做到,新的
class
写法只是让对象原型的写法更加清晰、更像面向对象编程的语法而已。上面的代码用 ES6 的
class
改写,就是下面这样。

class Point {
constructor(x, y) {
this.x =x;this.y =y;
}

toString() {
return '(' + this.x + ', ' + this.y + ')';
}
}

上面代码定义了一个“类”,可以看到里面有一个
constructor
方法,这就是构造方法,而
this
关键字则代表实例对象。也就是说,ES5 的构造函数
Point
,对应 ES6 的
Point
类的构造方法。

Point
类除了构造方法,还定义了一个
toString
方法。注意,定义“类”的方法的时候,前面不需要加上
function
这个关键字,直接把函数定义放进去了就可以了。另外,方法之间不需要逗号分隔,加了会报错。

Class 可以通过
extends
关键字实现继承,这比 ES5 的通过修改原型链实现继承,要清晰和方便很多。

class Point {
}

class ColorPoint extends Point {
}

上面代码定义了一个
ColorPoint
类,该类通过
extends
关键字,继承了
Point
类的所有属性和方法。

有了这些知识准备,那么我们来定义一个API接口的封装类,如下 base-api.js 代码所示。

//定义框架里面常用的API接口:Get/GetAll/Create/Update/Delete/Count等
export defaultclass BaseApi {
constructor(baseurl) {
this.baseurl =baseurl
}
//获取指定的单个记录 Get(data) {returnrequest({
url:
this.baseurl + 'Get',
method:
'get',
params: data
})
}
//根据条件获取所有记录 GetAll(data) {returnrequest({
url:
this.baseurl + 'GetAll',
method:
'get',
params: data
})
}
//创建记录 Create(data) {returnrequest({
url:
this.baseurl + 'Create',
method:
'post',
data: data
})
}
//更新记录 Update(data) {returnrequest({
url:
this.baseurl + 'Update',
method:
'put',
data: data
})
}
//删除指定数据 Delete(data) {returnrequest({
url:
this.baseurl + 'Delete',
method:
'delete',
params: data
})
}
//获取条件记录数量 Count(data) {returnrequest({
url:
this.baseurl + 'Count',
method:
'post',
data: data
})
}
}

以上我们定义了很多常规的ABP后端接口的封装处理,其中我们调用的地址通过组合的方式处理,而具体的地址则交由子类(业务对象API)进行赋值处理。

加入我们定义子类有DIctType、DictData等业务类,那么这些类继承BaseApi,就会具有相关的接口了,如下所示继承关系。

例如,我们对于DictDataApi的JS类定义如下所示。

通过一行代码 export default new Api('/abp/services/app/dictdata/') 就可以构造一个子类实例供使用了。

对于DictTypeApi来说,处理方式也是类似,继承自基类,并增加一些自己的接口实现即可。

这些API类的文件视图如下所示。

有了这些准备,我们就可以在视图页面类中导入这些定义,并使用JS类了。

//业务API对象
import dicttype from '@/api/dicttype'import dictdata from'@/api/dictdata'

加入我们要在视图页面中查询结果,直接就可以通过使用dictdata或者dicttype对象来实现对应的API调用,如下代码所示。

getlist() {//构造常规的分页查询条件
      var param ={
SkipCount: (
this.pageinfo.pageindex - 1) * this.pageinfo.pagesize,
MaxResultCount:
this.pageinfo.pagesize,//过滤条件 Name: this.searchForm.name,
Remark:
this.searchForm.remark,
DictType_ID:
this.searchForm.dictType_ID
};
//获取产品列表,绑定到模型上,并修改分页数量 this.listLoading = truedictdata.GetAll(param).then(data => {this.list =data.result.itemsthis.pageinfo.total =data.result.totalCountthis.listLoading = false})
}

或者如下代码所示。

    //删除指定字典类型
deleteDictType() {if (!this.searchForm.dictType_ID || typeof (this.searchForm.dictType_ID) === 'undefined') {return;
}
this.$confirm('您确认删除选定类型吗?', '操作提示',
{
type:
'warning' //success,error,info,warning //confirmButtonText: '确定', //cancelButtonText: '取消' }
).then(()
=>{var param = { id: this.searchForm.dictType_ID }
dicttype.Delete(param).then(data
=> {if(data.success) {//提示信息 this.$message({
type:
'success',
message:
'删除成功!'})//刷新数据 this.getTree();
}
})
})
}

最后我们来看看使用这些接口处理,对字典管理界面的实现。

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

循序渐进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 前端应用开发(12)--- 整合ABP框架的前端登录处理
》简单的介绍了一个结合ABP后端的登陆接口实现前端系统登陆的功能,本篇随笔继续深化这一主题,着重介绍基于ABP后端接口信息,实现对前端界面的开发工作。

ABP(
ASP.NET Boilerplate
)框架主要是基于.net core 进行的后端Web API的开发,结合Swagger的管理界面我们可以看到发布的 API 的接口明细信息,这样前端技术人员可以很容易整合前端的API应用。Vue + Element的前端应用,是目前较为流行的前端技术整合,Vue提供了前端框架很好的支持,Element提供了非常不错的界面组件封装和处理,通过ABP后端API接口和前端Vue+Element的整合,可以很好实现前后端的分离处理,同时又极大提高各自开发过程,并利用最新、应用广泛的技术来实现最好的技术应用。

1、ABP接口和前端对接处理

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

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

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

关于ABP框架使用,如果不知道,请自行补习一下我的随笔:
ABP框架使用

整理后的ABP快速开发框架的架构图示,如下图所示(以字典模块为例说明)

针对Web API接口调用的封装,为了适应客户端快速调用的目的,这个封装作为一个独立的封装层,以方便各个模块之间进行共同调用。

在基于VUE+Element 前端应用中,上图的ApiCaller组件,其实就是我们封装的API的JS类,同时也有相关的继承封装处理,类似C#中类的继承关系了。

在JS里面引入了ES6的语法,JS函数就可以使用类的方式来实现各种基础接口的封装和子类的继承关系了。

例如我们先定义好JS中常规的API封装接口BaseApi类,然后定义子类有DIctType、DictData等业务类,那么这些类继承BaseApi,就会具有相关的接口了,如下所示继承关系。

这些API类的文件视图如下所示。

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

一般来说,我们页面模块可能会涉及到Store模块,用来存储对应的状态信息,也可能是直接访问API模块,实现数据的调用并展示。在页面开发过程中,多数情况下,不需要Store模块进行交互,一般只需要存储对应页面数据为全局数据状态的情况下,才可能启用Store模块的处理。

通过WebProxy代理的处理,我们可以很容易在前端中实现跨域的处理,不同的路径调用不同的域名地址API都可以,最终转换为本地的API调用,这就是跨域的处理操作。

2、ABP接口信息和前端界面处理

有了上面的一些知识准备,相信对ABP+Vue+Element的前端对接有了一个大概的认识了。

ABP+Swagger负责API接口的开发和公布,如下是API接口的管理界面。

进一步查看GetAll的API接口说明,我们可以看到对应的条件参数,如下所示。

这些是作为查询条件的处理,用来给后端获取对应的条件信息,从而过滤返回的数据记录的。

那么我们前端界面也需要根据这些参数来构造查询界面,我们可以通过部分条件进行处理即可,其中MaxResultCount和SkipCount是用于分页定位的参数。

前端界面代码如下所示。

主要就是构造一个条件查询的表单如下所示。

其中定义了一个searchForm的属性,那么我们可以了解下它的定义。

然后我们在查询处理的函数getlist里面,就可以根据这些条件,以及分页参数进行数据的请求查询了,如下代码所示。

    getlist() { //列表数据获取
      var param = { //构造常规的分页查询条件
       SkipCount: (this.pageinfo.pageindex - 1) * this.pageinfo.pagesize,
MaxResultCount: this.pageinfo.pagesize,
//过滤条件 Name: this.searchForm.name,
Remark:
this.searchForm.remark,
DictType_ID:
this.searchForm.dictType_ID
};
//获取产品列表,绑定到模型上,并修改分页数量 this.listLoading = truedictdata.GetAll(param).then(data => {this.list =data.result.itemsthis.pageinfo.total =data.result.totalCountthis.listLoading = false})
},

其中的dictdata.GetAll就是调用API模块里面的函数进行处理,是我们在视图页面类中导入这些API类的定义的。

//业务API对象
import dicttype from '@/api/dicttype'import dictdata from'@/api/dictdata'

我们对于DictDataApi的JS类定义如下所示。

其中JS类的BaseApi具有常规的增删改查接口,如下所示。

其中list是列表的数据,pageinfo是分页信息,那么我们在前端的列表展示界面代码如下所示。

        <el-tablev-loading="listLoading":data="list"border
fit
stripe
highlight-current-row
:header-cell-style
="{background:'#eef1f6',color:'#606266'}"@selection-change="selectionChange"@row-dblclick="rowDbclick" > <el-table-columntype="selection"width="55" /> <el-table-columnlabel="字典名称"> <templateslot-scope="scope">{{ scope.row.name }}</template> </el-table-column> <el-table-columnalign="center"label="字典值"> <templateslot-scope="scope">{{ scope.row.value }}</template> </el-table-column> <el-table-columnlabel="备注"> <templateslot-scope="scope">{{ scope.row.remark }}</template> </el-table-column> <el-table-columnalign="center"label="排序"width="80"> <templateslot-scope="scope">{{ scope.row.seq }}</template> </el-table-column> <el-table-columnlabel="操作"width="140"> <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-row> </template> </el-table-column> </el-table> <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>

这样就可以简单实现列表的查询和展示了。

当然我们一般情况下,可能有一些列表用来进行数据过滤处理的,如这里的字典类型,可以通过树列表的进行展示,从而可以友好的管理不同类型的字典数据,如下是整合了树形列表的查询处理过程,界面相对复杂一些,不过原理差不多,都是根据条件进行API数据的请求,然后展示在列表中即可。

完整的对字典管理界面的实现。

其中包括对字典大类的维护,以及对应字典大类的数据列表数据的添加处理。

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

循序渐进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+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变量方式解决弹出编辑对话框界面无法触发更新的问题