基于 DevExpress 从零开始搭建多租户自洽的权限数据配置模块(二)
基础数据的维护管理,以简单基本操作的形式展开。主要是演示devexpress做基本的增删改查、加载表单、建立多表关联、用户操作动态加载数据等。
今天我们来简单介绍一下主界面如何利用Mdi控件跳转到各个子界面,并拿用户信息维护来举例,详细介绍一下基础数据维护的设计逻辑。
1、主界面的设计
首先我们来看一下主界面的设计:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace HiAuth2021
{
public partial class HiAuthManageSystem : DevExpress.XtraEditors.XtraForm
{
/// <summary>
///
/// </summary>
public HiAuthManageSystem()
{
InitializeComponent();
this.Shown += HiAuthManageSystem_Shown;
}
/// <summary>
///
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void HiAuthManageSystem_Shown(object sender, EventArgs e)
{
//在这里将需要全局访问的主界面对象,放到全局的状态管理器中去,作为系统初始化数据的一部分
HiAuthStaticSetting.MainForm = this;
HiAuthStaticSetting.SplashManager = splashScreenManager1;
HiAuthStaticSetting.Alert = alertControl1;
HiAuthStaticSetting.CurrentTenancy = staticTenancyInfoStatus;
HiAuthStaticSetting.CurrentLogin = staticLoginInfoStatus;
HiAuthStaticSetting.CurrentLocation = staticLocationInfoStatus;
HiAuthStaticSetting.Mdi = xtraTabbedMdiManager1;
}
/// <summary>
/// 超级用户管理
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void btnSuperUserManage_ItemClick(object sender, DevExpress.XtraBars.ItemClickEventArgs e)
{
//跳转子窗体的时候,将子窗体的MdiParent属性设为主界面对象本身,就使他们建立了联系
new HiAuth2021.HiAuthBasics.HiAuthAdminsManage() { MdiParent = this }.Show();
}
/// <summary>
/// 系统用户管理
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void btnSystemUsersManage_ItemClick(object sender, DevExpress.XtraBars.ItemClickEventArgs e)
{
new HiAuth2021.HiAuthBasics.HiAuthUsersManage() { MdiParent = this }.Show();
}
/// <summary>
/// 系统托管资源
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void btnSystemResourcesManage_ItemClick(object sender, DevExpress.XtraBars.ItemClickEventArgs e)
{
new HiAuth2021.HiAuthBasics.HiAuthResourcesManage() { MdiParent = this }.Show();
}
/// <summary>
/// 多租户管理
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void btnMultiTenancysManage_ItemClick(object sender, DevExpress.XtraBars.ItemClickEventArgs e)
{
new HiAuth2021.HiAuthBasics.HiAuthTenancysManage() { MdiParent = this }.Show();
}
/// <summary>
/// 切换租户
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void btnCuttingTenancy_ItemClick(object sender, DevExpress.XtraBars.ItemClickEventArgs e)
{
new HiAuthTenancyCutting() { StartPosition = FormStartPosition.CenterScreen }.ShowDialog();
}
/// <summary>
/// 公司管理
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void btnCompanysManage_ItemClick(object sender, DevExpress.XtraBars.ItemClickEventArgs e)
{
new HiAuth2021.HiAuthBasics.HiAuthCompanysManage() { MdiParent = this }.Show();
}
/// <summary>
/// 角色管理
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void btnRolesManage_ItemClick(object sender, DevExpress.XtraBars.ItemClickEventArgs e)
{
new HiAuth2021.HiAuthBasics.HiAuthRolesManage() { MdiParent = this }.Show();
}
/// <summary>
/// 岗位管理
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void btnDutysManage_ItemClick(object sender, DevExpress.XtraBars.ItemClickEventArgs e)
{
new HiAuth2021.HiAuthBasics.HiAuthDutysManage() { MdiParent = this }.Show();
}
/// <summary>
/// 部门管理
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void btnDepartmentsManage_ItemClick(object sender, DevExpress.XtraBars.ItemClickEventArgs e)
{
new HiAuth2021.HiAuthBasics.HiAuthDepartmentsManage() { MdiParent = this }.Show();
}
/// <summary>
/// 退出系统
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void 退出ToolStripMenuItem_Click(object sender, EventArgs e)
{
System.Environment.Exit(0);
}
/// <summary>
/// 关闭所有子界面
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void btnCloseAllMdiForms_ItemClick(object sender, DevExpress.XtraBars.ItemClickEventArgs e)
{
HiAuthStaticSetting.CloseMdiPagesOpenning();
}
}
}
在这里我们有几个要点需要注意:
- 主界面需要引入XtraTabbedMdiManager控件,用于以多页Tab页的形式,组织所有的子窗体用约定的形式展开。
- 主界面窗体的IsMdiContainer属性的值需要配置为true。(确定该窗体是否是MDI容器)
- 子窗体Show之前,指定子窗体的MdiParent属性为主界面对应的窗体对象。
/// <summary>
/// 超级用户管理
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void btnSuperUserManage_ItemClick(object sender, DevExpress.XtraBars.ItemClickEventArgs e)
{
//跳转子窗体的时候,将子窗体的MdiParent属性设为主界面对象本身,就使他们建立了联系
new HiAuth2021.HiAuthBasics.HiAuthAdminsManage() { MdiParent = this }.Show();
}
到这里,主界面和他的Mdi子窗体之间的联系就建立完毕了,接下来我们进行子界面的常见场景设计。
2、用户信息维护
我们把业务数据的前后交互通道分成了三层。分别是UI交互、Api交互、数据库交互。
UI交互的核心内容是请求数据进行呈现,收集数据进行提交。简单逻辑是这样来设计的:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace HiAuth2021.HiAuthBasics
{
public partial class HiAuthUsersManage : XtraFormBaseTenancy
{
private bool isNeedPass = false;
private List<DbModels.t_auth_users> source;
public HiAuthUsersManage()
{
InitializeComponent();
this.Shown += HiAuthUsersManage_Shown;
gridView1.RowCellClick += GridView1_RowCellClick;
gridView1.FocusedRowChanged += GridView1_FocusedRowChanged;
gridView1.SelectionChanged += GridView1_SelectionChanged;
}
/// <summary>
/// 多选用户时,加载被选中信息展示给操作者
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void GridView1_SelectionChanged(object sender, DevExpress.Data.SelectionChangedEventArgs e)
{
var usersSelected = gridView1.GetSelectedRows().ToList().Where(w =>w >=0).ToList();
if (usersSelected.Count > 0)
{
var usersLst = new List<DbModels.t_auth_users>();
string selectedUsersStr = "";
usersSelected.ForEach(f => { usersLst.Add(gridView1.GetRow(f) as DbModels.t_auth_users); });
usersLst.ForEach(f => { selectedUsersStr += f.user_code + f.user_name + "|"; });
memoEdit1.EditValue = selectedUsersStr.Remove(selectedUsersStr.Length - 1);
}
}
/// <summary>
/// 根据点击的用户信息异步加载用户所归属的角色信息集合
/// </summary>
/// <param name="user_id"></param>
private void GetHiAuthUserAssignedRoles(int user_id)
{
gridView2.Appearance.Row.ForeColor = Color.White;
List<DbModels.t_auth_roles> result = new List<DbModels.t_auth_roles>();
var rss = Task.Run(async () =>
{
var rolesJson = await new HiAuthBasicsRestBussiness.HiAuthUserRestBusiness().GetHiAuthUserAssignedRoles(user_id);
var roles = Newtonsoft.Json.JsonConvert.DeserializeObject<DtoModels.LayuiJsonResult<DbModels.t_auth_roles>>(rolesJson);
return roles.data;
});
var waiter = rss.GetAwaiter();
waiter.OnCompleted(() =>
{
gridControl2.DataSource = rss.Result;
gridView2.Appearance.Row.ForeColor = Color.Black;
});
}
/// <summary>
/// 焦点变化加载
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void GridView1_FocusedRowChanged(object sender, DevExpress.XtraGrid.Views.Base.FocusedRowChangedEventArgs e)
{
//焦点变换和行点击互斥
if (isNeedPass)
{
isNeedPass = false;
}
if (e.FocusedRowHandle >=0)
{
var user = gridView1.GetRow(e.FocusedRowHandle) as DbModels.t_auth_users;
dataLayoutControl1.DataSource = user;
GetHiAuthUserAssignedRoles(user.object_id);
isNeedPass = true;
}
}
/// <summary>
/// 行点击变换加载
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void GridView1_RowCellClick(object sender, DevExpress.XtraGrid.Views.Grid.RowCellClickEventArgs e)
{
//焦点变换和行点击互斥
if (isNeedPass)
{
isNeedPass = false;
}
if (e.RowHandle >= 0)
{
var user = gridView1.GetRow(e.RowHandle) as DbModels.t_auth_users;
dataLayoutControl1.DataSource = user;
GetHiAuthUserAssignedRoles(user.object_id);
isNeedPass = true;
}
}
/// <summary>
/// Shown事件加载内容
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void HiAuthUsersManage_Shown(object sender, EventArgs e)
{
HiAuthStaticSetting.SetWaittingFormOpen(this);
btnRefresh.PerformClick();
HiAuthStaticSetting.SetWaittingFormClose(this);
}
/// <summary>
/// 保存样式
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void btnSaveStyle_ItemClick(object sender, DevExpress.XtraBars.ItemClickEventArgs e)
{
}
/// <summary>
/// 清除样式
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void btnClearStyle_ItemClick(object sender, DevExpress.XtraBars.ItemClickEventArgs e)
{
}
/// <summary>
/// 数据刷新
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void btnRefresh_ItemClick(object sender, DevExpress.XtraBars.ItemClickEventArgs e)
{
//加载用户信息
gridControl1.DataSource = source = RestHelper<DbModels.t_auth_users>.GetDataSourceByRestRequest(() =>
{
return new HiAuthBasicsRestBussiness.HiAuthUserRestBusiness().GetHiAuthAllUsers();
});
//加载角色下拉框信息
searchLookUpEdit1.Properties.DataSource = RestHelper<DbModels.t_auth_roles>.GetDataSourceByRestRequest(() =>
{
return new HiAuthBasicsRestBussiness.HiAuthRoleRestBusiness().GetHiAuthAllRoles();
});
}
/// <summary>
/// 批量分配角色
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void btnBatchRoleAssign_Click(object sender, EventArgs e)
{
var selectedUsersRows = gridView1.GetSelectedRows().ToList();
var selectedUsers = new List<int>();
selectedUsersRows.ForEach((f) => { selectedUsers.Add((gridView1.GetRow(f) as DbModels.t_auth_users).object_id); });
if (selectedUsers.Count > 0)
{
var assignedRoleId = searchLookUpEdit1.EditValue.ToNullableInt32();
if (assignedRoleId != null && assignedRoleId >= 0)
{
var result = RestHelper<object>.DoExcuteCommandAndReturnResult(() =>
{
return new HiAuthBasicsRestBussiness.HiAuthUserRestBusiness().BatchAssignUsersToRoleId(selectedUsers, assignedRoleId);
});
if (result.result)
{
HiAuthStaticSetting.AlertMsg(this,result.msg);
}
else
{
HiAuthStaticSetting.AlertErrorMsg(this, result.msg);
}
}
}
}
/// <summary>
/// 批量禁用用户
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void btnBatchForbiddenUsers_Click(object sender, EventArgs e)
{
}
/// <summary>
/// 保存修改
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void btnSaveEdit_Click(object sender, EventArgs e)
{
var user = dataLayoutControl1.DataSource as DbModels.t_auth_users;
var editResultJson = new HiAuthBasicsRestBussiness.HiAuthUserRestBusiness().SaveEditResultOfUser(user);
var result = Newtonsoft.Json.JsonConvert.DeserializeObject<DtoModels.LayuiJsonResult<DbModels.t_auth_users>>(editResultJson);
HiAuthStaticSetting.AlertMsg(this,result.msg);
}
/// <summary>
/// 新增用户
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void btnAddNewEmptyUser_Click(object sender, EventArgs e)
{
var usersJson = new HiAuthBasicsRestBussiness.HiAuthUserRestBusiness().NewEmptyUserAndReturn();
var users = Newtonsoft.Json.JsonConvert.DeserializeObject<DtoModels.LayuiJsonResult<DbModels.t_auth_users>>(usersJson);
source.AddRange(users.data);
gridView1.RefreshData();
}
}
}
Api交互的核心内容是,承接UI层组织的数据进行接收和序列化并转发提交,承接数据库传递来的数据进行序列化转化和向UI层转发。
简单逻辑是这样来设计的:
using HiAuth2021.DbModels;
using HiAuth2021.DtoModels;
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace HiAuth2021.HiAuthBasicsRestBussiness
{
public class HiAuthUserRestBusiness
{
/// <summary>
/// 请求所有用户数据
/// </summary>
/// <returns></returns>
public string GetHiAuthAllUsers()
{
var users = new HiAuthBasicsBussiness.HiAuthUserBussiness().GetHiAuthAllUsers();
var jsonResult = new LayuiJsonResult<DbModels.t_auth_users>()
{
code = 200,
data = users,
count = users.Count,
msg = "success"
};
return JsonConvert.SerializeObject(jsonResult);
}
/// <summary>
/// 请求分页用户数据
/// </summary>
/// <param name="page">页码</param>
/// <param name="limit">条数</param>
/// <returns></returns>
public string GetHiAuthPageUsers(int page,int limit)
{
var users = new HiAuthBasicsBussiness.HiAuthUserBussiness().GetHiAuthPageUsers(page,limit);
var jsonResult = new LayuiJsonResult<DbModels.t_auth_users>()
{
code = 200,
data = users,
count = users.Count,
msg = "success"
};
return JsonConvert.SerializeObject(jsonResult);
}
/// <summary>
/// 新增一条空白用户记录
/// </summary>
/// <returns></returns>
public string NewEmptyUserAndReturn()
{
var user = new HiAuthBasicsBussiness.HiAuthUserBussiness().NewEmptyUserAndReturn();
var jsonResult = new LayuiJsonResult<DbModels.t_auth_users>()
{
code = 200,
data = new List<DbModels.t_auth_users>() { user},
count = 1,
msg = "success"
};
return JsonConvert.SerializeObject(jsonResult);
}
/// <summary>
/// 新增一条空白用户记录
/// </summary>
/// <returns></returns>
public string SaveEditResultOfUser(t_auth_users user)
{
var userEdit = new HiAuthBasicsBussiness.HiAuthUserBussiness().SaveEditResultOfUser(user);
if (userEdit)
{
var jsonResult = new LayuiJsonResult<DbModels.t_auth_users>()
{
code = 200,
data = null,
count = 1,
msg = "success"
};
return JsonConvert.SerializeObject(jsonResult);
}
else
{
var jsonResult = new LayuiJsonResult<DbModels.t_auth_users>()
{
code = 200,
data = null,
count = 1,
msg = "failed"
};
return JsonConvert.SerializeObject(jsonResult);
}
}
public async Task<string> GetHiAuthUserAssignedRoles(int object_id)
{
var roles = await new HiAuthBasicsBussiness.HiAuthUserBussiness().GetHiAuthUserAssignedRoles(object_id);
var jsonResult = new LayuiJsonResult<DbModels.t_auth_roles>()
{
code = 200,
data = roles,
count = roles.Count,
msg = "success"
};
return JsonConvert.SerializeObject(jsonResult);
}
public string BatchAssignUsersToRoleId(List<int> selectedUsers, int? assignedRoleId)
{
var updateResult = new HiAuthBasicsBussiness.HiAuthUserBussiness().BatchAssignUsersToRoleId(selectedUsers,assignedRoleId);
if (updateResult)
{
var jsonResult = new LayuiJsonResult()
{
code = 200,
count = selectedUsers.Count,
msg = "批量分配角色成功!",
result = true
};
return JsonConvert.SerializeObject(jsonResult);
}
else
{
var jsonResult = new LayuiJsonResult()
{
code = 200,
count = selectedUsers.Count,
msg = "批量分配角色失败!",
result = false
};
return JsonConvert.SerializeObject(jsonResult);
}
}
}
}
数据库交互的核心内容就比较显而易见了,那就是针对数据库的增删改查、各种关联查询、聚合查询、排序、逻辑组织等等。
using HiAuth2021.DbModels;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace HiAuth2021.HiAuthBasicsBussiness
{
public class HiAuthUserBussiness
{
/// <summary>
/// 请求所有用户数据
/// </summary>
/// <returns></returns>
public List<t_auth_users> GetHiAuthAllUsers()
{
return Db.DbHiAuth.Queryable<t_auth_users>().ToList();
}
/// <summary>
/// 请求所有用户数据
/// </summary>
/// <returns></returns>
public async Task<List<t_auth_roles>> GetHiAuthUserAssignedRoles(int user_id)
{
var links = await Db.DbHiAuth.Queryable<t_auth_link_role_user>()
.Where(w => w.user_id == user_id)
.Select(s => s.role_id)
.Distinct()
.ToListAsync();
var roles = await Db.DbHiAuth.Queryable<t_auth_roles>()
.Where(w => links.Contains(w.object_id))
.ToListAsync();
return roles;
}
/// <summary>
/// 请求分页用户数据
/// </summary>
/// <param name="page">页码</param>
/// <param name="limit">条数</param>
/// <returns></returns>
public List<t_auth_users> GetHiAuthPageUsers(int page,int limit)
{
return Db.DbHiAuth.Queryable<t_auth_users>().ToPageList(page,limit);
}
/// <summary>
/// 新增一条空白用户记录
/// </summary>
/// <returns></returns>
public t_auth_users NewEmptyUserAndReturn()
{
var user = new t_auth_users()
{
};
return Db.DbHiAuth.Insertable(user).ExecuteReturnEntity();
}
public bool SaveEditResultOfUser(t_auth_users user)
{
return Db.DbHiAuth.Updateable(user).ExecuteCommandHasChange();
}
public bool BatchAssignUsersToRoleId(List<int> selectedUsers, int? assignedRoleId)
{
try
{
foreach (var user in selectedUsers)
{
if (!Db.DbHiAuth.Queryable<DbModels.t_auth_link_role_user>().Any(a => a.user_id == user && a.role_id == assignedRoleId))
{
Db.DbHiAuth.Insertable(new DbModels.t_auth_link_role_user()
{
user_id = user,
role_id = assignedRoleId,
link_status = 1,
create_time = DateTime.Now,
create_man = "test"
}).ExecuteCommand();
}
else
{
var link = Db.DbHiAuth.Queryable<DbModels.t_auth_link_role_user>().Single(a => a.user_id == user && a.role_id == assignedRoleId);
if (link.link_status != 1)
{
link.link_status = 1;
}
Db.DbHiAuth.Updateable(link).ExecuteCommand();
}
}
return true;
}
catch (Exception)
{
return false;
}
}
}
}
通过简单的三层传递,就完成了用户数据的加载呈现、表单加载、表单提交等等基本操作。
在这里,值得注意的是,我们定义了几个DTO结构,用户前后通信时的标准范式的约定。将来我们把RestBussiness和Bussiness放到Web服务端时,这会极大的降低我们的迁移工作量。
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace HiAuth2021.DtoModels
{
/// <summary>
/// layui格式restful返回值
/// </summary>
/// <typeparam name="T"></typeparam>
public class LayuiJsonResult<T>
{
/// <summary>
/// 响应码
/// </summary>
public int code { get; set; }
/// <summary>
/// 数据集数量
/// </summary>
public int count { get; set; }
/// <summary>
/// 返回信息
/// </summary>
public string msg { get; set; }
/// <summary>
/// 数据集
/// </summary>
public List<T> data { get; set; }
}
public class LayuiJsonResult
{
/// <summary>
/// 响应码
/// </summary>
public int code { get; set; }
/// <summary>
/// 数据集数量
/// </summary>
public int count { get; set; }
/// <summary>
/// 返回信息
/// </summary>
public string msg { get; set; }
/// <summary>
/// 提交结果
/// </summary>
public bool result { get; set; }
}
}
关于基础数据的维护和提交逻辑,基本就陈述清楚了。接下来的几天,我们将把其他的基础数据维护,根据不同的用户使用场景进行逐个展开,需要关联维护的、基本信息维护的、权限配置的、约定租户范围的等等。