返回總目錄:ABP+AdminLTE+Bootstrap Table權限管理系統一期
寫在前面的話
很多人說ABP不適合高並發大型,有一定的道理,但是我覺得還是可以的,就看架構師的能力了,我之前公司就是ABP絕對百萬數據級項目,是一個在線教育網站,涉及到平台,學院,院系,班級,課程,學生等,一個平台多少大學,一個大學多少院系,一個院系多少班級多少課程,其負責程度一點都不簡單,不說了,那是大神,比我在園子看到絕對大多數架構師都強悍.是我等仰望都對象.但是這不是停下腳步仰望的理由,只會是我們追求更強的腳步.
軟件開發中會有大量機械重復的工作,也有大量重復的代碼,用戶需求越來越高,我們要做出的響應也越來越復雜,這就需要我們去集成更多的東西來應付工作的需要。
每當我們要開發一個新的系統的時候,我們要用到以前用到過的東西,比如mvc,ioc,日志,數據庫的映射,日志管理,消息隊列組件等等。我們更希望把更多時間時間用來處理業務邏輯,而不是花在軟件結構,日志,容錯等問題。
很多大公司都有自己的基礎框架,自己公司封裝了很多東西,像我們公司的日期組件,彈窗,表格樣式,分頁等等都是已經封裝好了的,再后期開發的時候我們只需要去調用一下就可以了,不需要每個控件都自己再花時間和精力去封裝。
這節我就來說一下在ABP module-zero基礎上做AdminLTE+Bootstrap Table的系統,算是前面十一節的總結和擴展.
首先我們依舊去官網根據abp模板創建解決方案.勾選上module-zero,然后創建數據庫連接,還原nuget包,然后update-database創建數據庫.
接下來就是創建腳本更新數據庫了,以上這些都在前面的章節講到了,我就不做累述了,不明白可回去一下第一節.
然后在home控制器下建ActionResult login,添加一個試圖頁面.加上自己的登陸頁面樣式js等,這里我們就不用mvc的形式再在去請求控制器 了,我們直接請求webapi的登陸方法了.是的就是已經搭好了swagger的然后請求/swagger/ui/index的Account接口.如圖.
abp javascript ajax的封裝及應用
既然前面講到ABP 對javascript ajax的封裝
var newPerson = {
name: 'Dougles Adams', age: 42 }; abp.ajax({ url: '/People/SavePerson', data: JSON.stringify(newPerson) }).done(function(data) { abp.notify.success('created new person with id = ' + data.personId); });
其實這里我們還可以做一些再次封裝,方便在項目中去使用,就以登陸為例效果如下。
abp.ui.block($('#login'));
var url = "/api/Account"; var login = function (para, ajaxtype,posturl) { return abp.ajax({ url: posturl, type: ajaxtype, async: false, data: JSON.stringify(para) }); }; var loginModel = { "tenancyName": "", "usernameOrEmailAddress": $("#userName").val(), "password": $("#password").val() }; abp.ui.setBusy( $('#login'), login(loginModel, "post", url).done(function (data) { abp.auth.setToken("Bearer " + data); window.location.href = "/admin/userinfo/index" }), );
abp.ui.block
當然這是在ABP原來封裝的效果上加上的,細心的你已經發現這里多了兩個東西,一個是abp.ui.block,另外一個是abp.ui.setBusy,這其實是一個阻止用戶重復提交,和正在提交繁忙狀態,
其實就是一個遮罩層。
這里是ABP集成的jquery.blockUI.js插件,該API使用一個透明的塗層(transparent overlay)來阻塞整個頁面或者該頁面上的一個元素。這樣,用戶的點擊就無效了。當保存一個表單或者加載一個區域(一個div或者整個頁面)時這是很有用的。比如
另外abpjs中也對blockUI做了一些常用方法的封裝,設置阻塞abp.ui.block,取消阻塞abp.ui.unblock ,設置繁忙狀abp.ui.setBusy 和解除繁忙狀態abp.ui.clearBusy
abp.ui.block = function (elm) {
abp.log.warn('abp.ui.block is not implemented!'); }; abp.ui.unblock = function (elm) { abp.log.warn('abp.ui.unblock is not implemented!'); }; /* UI BUSY */ //Defines UI Busy API, not implements it abp.ui.setBusy = function (elm, optionsOrPromise) { abp.log.warn('abp.ui.setBusy is not implemented!'); }; abp.ui.clearBusy = function (elm) { abp.log.warn('abp.ui.clearBusy is not implemented!'); };
abp.ui.block(); //阻塞整個頁面 abp.ui.block($('#MyDivElement')); //可以使用jQuery 選擇器.. abp.ui.block('#MyDivElement'); //..或者直接使用選擇器 abp.ui.unblock(); //解除阻塞整個頁面 abp.ui.unblock('#MyDivElement'); //解除阻塞特定的元素
abp.blockUI
UI Block API默認使用jQuery的blockUI插件實現的。要是它生效,你應該包含它的javascript文件,然后在頁面中包含abp.blockUI.js作為適配器。
另外一個就是busy 該API用於使得某些頁面或者元素處於繁忙狀態。比如,你可能想阻塞一個表單,然后當提交表單至服務器時展示一個繁忙的指示器。例子:
abp.ui.setBusy('#MyLoginForm');
abp.ui.clearBusy('#MyLoginForm');
效果就是上面的繁忙效果。
該參數應該是一個選擇器(如‘#MyLoginForm’)或者jQuery選擇器(如$('#MyLoginForm'))。要使得整個頁面處於繁忙狀態,你可以傳入null(或者'body')作為選擇器。setBusy函數第二個參數接收一個promise(約定),當該約定完成時會自動清除繁忙的狀態。因為abp.ajax返回promise,我們可以直接將它作為promise傳入。要學習慣於promise更多的東西,查看jQuery的Deferred。
UI Busy API是使用spin.js實現的。要讓它生效,應該包含它的javascript文件,然后在頁面中包含abp.spin.js作為適配器。
經過上面的努力,我們得登陸也已經做好了。登陸成功之后我們要做事的事情就是一個保存token另外一個就是路由的重定向了。
Abp.AuthToken與cookie
token在ABP中很重要,我們在請求 /api/Account會反饋一個token,我們在登陸的時候就把token存到cookie中,以方便后面的使用。如登陸中的 abp.auth.setToken("Bearer " + data); 那ABP是怎么樣設置cookie的了,這里也做了封裝。
abp.auth.tokenCookieName = 'Abp.AuthToken';
abp.auth.setToken = function (authToken, expireDate) { abp.utils.setCookieValue(abp.auth.tokenCookieName, authToken, expireDate, abp.appPath); }; abp.auth.getToken = function () { return abp.utils.getCookieValue(abp.auth.tokenCookieName); } abp.auth.clearToken = function () { abp.auth.setToken(); }
這里面就包含了token常用的存取和清除的方法。頁面上緩存的cookie名字就是Abp.AuthToken,獲取的時候可以直接獲取。
model和DTO
我們在已經添加了域,所以這里登陸成功之后直接把url指向/admin/userinfo/index。當然在/Areas/Common/Views/Layout里面我們已經AdminLTE的布局了,包括菜單已經加載出來了,其實現在服務層的時候漏了一些東西,我們這里補上,ABP既然是一個框架
那么在創建Service的時候自然要包含基礎增刪查改的方法,那么這時候IAsyncCrudAppService就派上用場了。這里我們以模板IModulesService講一下。首先我們創建好model和DTO
using Abp.Domain.Entities;
using System; using System.Collections.Generic; using System.ComponentModel.DataAnnotations; using System.Linq; using System.Text; using System.Threading.Tasks; namespace JCms.Meuns { public class Meun : Entity<int>, IMayHaveTenant { public int? ParentId { get; set; } [Required] [StringLength(20)] public string Name { get; set; } [Required] [StringLength(50)] public string LinkUrl { get; set; } [StringLength(100)] public string Description { get; set; } public bool IsMenu { get; set; } public int Code { get; set; } public bool Enabled { get; set; } public DateTime UpdateDate { get; set; } public int? TenantId { get; set; } } }
DTO:
using Abp.Application.Services.Dto;
using Abp.AutoMapper; using Abp.Domain.Entities; using System; using System.Collections.Generic; using System.ComponentModel; using System.ComponentModel.DataAnnotations; using System.Linq; using System.Text; using System.Threading.Tasks; namespace JCms.Meuns { /// <summary> /// 菜單 /// </summary> [Serializable] [AutoMapFrom(typeof(Meun))] public class MeunDto : EntityDto<int> { /// <summary> /// id /// </summary> public int Id { get; set; } /// <summary> /// 父模塊Id /// </summary> public int? ParentId { get; set; } /// <summary> /// 名稱 /// </summary> [Required] [StringLength(20)] public string Name { get; set; } /// <summary> /// 鏈接地址 /// </summary> [Required] [StringLength(50)] public string LinkUrl { get; set; } /// <summary> /// 是否是菜單 /// </summary> public bool IsMenu { get; set; } /// <summary> /// 模塊編號 /// </summary> public int Code { get; set; } /// <summary> /// 描述 /// </summary> [StringLength(100)] public string Description { get; set; } /// <summary> /// 是否激活 /// </summary> public bool Enabled { get; set; } public DateTime UpdateDate { get; set; } //public virtual MeunDto ParentModule { get; set; } //public List<MeunDto> ChildModules { get; private set; } public List<MeunDto> children { get; set; } } }
這里要注意的如果model集成了某個接口,那么DTO也要繼承這個接口的DTO,不然再繼承IAsyncCrudAppService就會報錯。
比如面的model繼承Entity<int> 那么DTO也要繼承EntityDto<int>.
IAsyncCrudAppService
然后我們看一下IAsyncCrudAppService需要哪么參數。
這里都可以看得很清楚了,包括增刪查改的DTO這里我比較懶,都用了一個。
接口:
public interface IModulesService : IAsyncCrudAppService<MeunDto, int, PagedResultRequestDto, MeunDto, MeunDto> // IApplicationService
{
}
實現
public class ModulesService : AsyncCrudAppService<Meun, MeunDto, int, PagedResultRequestDto, MeunDto, MeunDto>, IModulesService
{
public ModulesService(IRepository<Meun, int> repository) : base(repository) { } }
apiJCMSWebApiModule
然后,我們在apiJCMSWebApiModule方法下加上.WithConventionalVerbs() 這樣我們就可以看到特定的HTTP前綴,不然全是post,HTTP動詞是通過方法名的前綴決定的:
- Get:方法名以Get開頭。
- Put:方法名以Put或Update開頭。
- Delete:方法名以Delete或Remove開頭。
- Post:方法名以Post或Create開頭。
- 否則,Post是HTTP動詞的默認值。
我們可以通過對特定的方法使用WithVerb方法或者HTTP特性來覆蓋上述慣例。
就這樣,我們在業務層中常用的增刪改查的方法就誕生了。
驗證一下,傳入參數,結果沒毛病,可用。當然這里根據自己的需要可以重寫這些方法的。頁面和前面的頁面差不多,沒啥講的,這里頁面增刪改查都已經實現。
首先我們看一下userinfo 頁面,這里我們也根據abp ajax的封裝和 swagger的應用做了一些改變,首先看頁面,我們不通過控制器去獲取創建和修改刪除的方法了。控制器只有一個帶分頁的獲取的方法 這是因為Bootstrap table必須要以這樣的json結構返回
控制器方法
using Abp.Application.Services.Dto; using Abp.Web.Models; using Abp.Web.Security.AntiForgery; using JCMS.Authorization.Users; using JCMS.Sessions.Dto; using JCMS.Users; using JCMS.Users.Dto; using JCMS.Web.Controllers; using System; using System.Collections.Generic; using System.Linq; using System.Web; using System.Web.Mvc; namespace JCMS.Web.Areas.Admin.Controllers { public class UserInfoController : JCMSControllerBase { private readonly IUserAppService _UserAppService; public UserInfoController( IUserAppService UserAppService) { _UserAppService = UserAppService; } public ActionResult Index() { return View(); } [DisableAbpAntiForgeryTokenValidation] [HttpGet] [DontWrapResult] public JsonResult GetUsersList() { string pageNumber = string.IsNullOrWhiteSpace(Request["pageNumber"]) ? "0" : Request["pageNumber"]; string pageSize = string.IsNullOrWhiteSpace(Request["pageSize"]) ? "20" : Request["pageSize"]; List<UserDto> Userlist = new List<UserDto>(); Userlist = _UserAppService.GetAllList(); int totaldata = Userlist.Count(); Userlist = Userlist.Skip(int.Parse(pageNumber) * int.Parse(pageSize)).Take(int.Parse(pageSize)).ToList(); var result = new { total = totaldata, rows = Userlist }; return Json(result, JsonRequestBehavior.AllowGet); } } }
DontWrapResult標簽打上的,不需要abp做的特殊封裝。js頁面的一些方法。

<script type="text/javascript"> $(function () { //1.初始化Table var oTable = new TableInit(); oTable.Init(); //2.初始化Button的點擊事件 var oButtonInit = new ButtonInit(); oButtonInit.Init(); }); var Url = "@Url.Action("GetUsersList")"; // var Url = "/api/services/app/user/GetAll()"; var TableInit = function () { var oTableInit = new Object(); //初始化Table oTableInit.Init = function () { $('#tb_departments').bootstrapTable({ // url: '../User/GetUsersList', url: Url, //請求后台的URL(*) method: 'get', //請求方式(*) toolbar: '#toolbar', //工具按鈕用哪個容器 striped: true, //是否顯示行間隔色 cache: false, //是否使用緩存,默認為true,所以一般情況下需要設置一下這個屬性(*) pagination: true, //是否顯示分頁(*) sortable: false, //是否啟用排序 sortOrder: "asc", //排序方式 queryParams: oTableInit.queryParams,//傳遞參數(*) sidePagination: "server", //分頁方式:client客戶端分頁,server服務端分頁(*) pageNumber: 1, //初始化加載第一頁,默認第一頁 pageSize: 2, //每頁的記錄行數(*) pageList: [10, 25, 50, 100], //可供選擇的每頁的行數(*) search: true, //是否顯示表格搜索,此搜索是客戶端搜索,不會進服務端,所以,個人感覺意義不大 strictSearch: true, showColumns: true, //是否顯示所有的列 showRefresh: true, //是否顯示刷新按鈕 minimumCountColumns: 2, //最少允許的列數 clickToSelect: true, //是否啟用點擊選中行 height: 500, //行高,如果沒有設置height屬性,表格自動根據記錄條數覺得表格高度 uniqueId: "ID", //每一行的唯一標識,一般為主鍵列 showToggle: true, //是否顯示詳細視圖和列表視圖的切換按鈕 cardView: false, //是否顯示詳細視圖 detailView: false, //是否顯示父子表 columns: [{ checkbox: true }, { field: 'UserName', title: '姓名' }, { field: 'EmailAddress', title: '郵箱' }, { field: 'Surname', title: '真是姓名' }, { field: 'Name', title: '角色' }, ] }); }; //得到查詢的參數 oTableInit.queryParams = function (params) { var temp = { //這里的鍵的名字和控制器的變量名必須一直,這邊改動,控制器也需要改成一樣的 limit: params.limit, //頁面大小 offset: params.offset, //頁碼 departmentname: $("#txt_search_departmentname").val(), statu: $("#txt_search_statu").val() }; return temp; }; return oTableInit; }; var ButtonInit = function () { var oInit = new Object(); var postdata = {}; oInit.Init = function () { //初始化頁面上面的按鈕事件 //查詢角色 $("#btn_query").click(function () { var actionUrl = "@Url.Action("GetUsersList")"; m_pagerow = 0; $("#tb_departments").bootstrapTable('refresh', { url: actionUrl }); }); //新增角色 $("#btn_add").click(function () { $("#id").val(""); $("#txt_Surname").val(""); $("#txt_Name").val(""); $("#txt_UserName").val(""); $("#txt_isDeleted").val(""); $("#myModalLabel").text("新增"); $('#myModal').modal(); }); //新增角色 $("#btn_submit").click(function () { var Id = $("#id").val() == "" ? 0 : $("#id").val(); var Url = "/api/services/app/user/Update"; var ajaxtype = "put"; if ($("#id").val() == "") { Url = "/api/services/app/user/Create"; ajaxtype = "post"; } var careteorUpdatePerson = function (person, ajaxtype) { return abp.ajax({ url: Url, type: ajaxtype, async: false, data: JSON.stringify(person) }); }; var newPerson = { "id": $("#id").val(), "UserName": $("#txt_Surname").val(), "EmailAddress" : $("#txt_Name").val(), "Name": $("#txt_UserName").val(), "Surname": "test", "Password": "123456" }; careteorUpdatePerson(newPerson, ajaxtype).done(function (data) { toastr.warning('操作成功!'); var actionUrl = "@Url.Action("GetUsersList")"; $("#tb_departments").bootstrapTable('refresh', { url: actionUrl }); }); }); //編輯角色 $("#btn_edit").click(function () { var arrselections = $("#tb_departments").bootstrapTable('getSelections'); if (arrselections.length > 1) { toastr.warning('只能選擇一行進行編輯'); return; } if (arrselections.length <= 0) { toastr.warning('請選擇有效數據'); return; } $("#id").val(arrselections[0].id); $("#txt_Surname").val(arrselections[0].UserName); $("#txt_Name").val(arrselections[0].EmailAddress); $("#txt_UserName").val(arrselections[0].Name); $("#txt_isDeleted").val(arrselections[0].Id); $("#myModalLabel").text("修改"); $('#myModal').modal(); }); //通常我們使用ajax會按照如下寫法,做一個簡單的封裝來重用ajax,此處框架可以幫你生成簡單的調用方法 var deletePerson = function (person) { return abp.ajax({ // url: abp.appPath + '/api/services/app/user/Delete', url:'/api/services/app/user/Delete', type: 'delete', async: false, data: JSON.stringify(person) }); }; //刪除角色 $("#btn_delete").click(function () { var arrselections = $("#tb_departments").bootstrapTable('getSelections'); if (arrselections.length > 1) { toastr.warning('只能選擇一行進行編輯'); return; } if (arrselections.length <= 0) { toastr.warning('請選擇有效數據'); return; } var Id = arrselections[0].id; var newPerson = { "id": Id }; //直接調用方法,如何生成上面的調用方法可以參考源碼中的Abp.Web.Api項目中/ WebApi/ Controllers/ Scripting/ jQuery下的實現 deletePerson(newPerson).done(function (data) { toastr.warning('操作成功!'); var actionUrl = "@Url.Action("GetUsersList")"; $("#tb_departments").bootstrapTable('refresh', { url: actionUrl }); }); }); //權限授權 $("#btn_authorize").click(function () { var arrselections = $("#tb_departments").bootstrapTable('getSelections'); if (arrselections.length > 1) { toastr.warning('只能選擇一個角色進行授權'); return; } if (arrselections.length <= 0) { toastr.warning('請選擇有效數據'); return; } var actionUrl = "@Url.Action("AuthorizePermission")"; var param = { id: arrselections[0].Id }; ShowModal_Authorize(actionUrl, param, "權限授權"); }); //模態框中“權限授權”保存 var $modal = $("#authorizeModal"); $("#btnSave", $modal).click(function () { var actionUrl = "@Url.Action("AuthorizePermission")"; SaveModal_Authorize(actionUrl); }); //模態框中“新增編輯角色”保存 var $formmodal = $("#modal-form"); $("#btnSave", $formmodal).click(function () { var $tb = $("#tb_departments"); SaveModal($tb); }); /*******彈出表單*********/ function ShowModal(actionUrl, param, title) { debugger; var $modal = $("#modal-form"); //表單初始化 $(".modal-title", $modal).html(title); $("#modal-content", $modal).attr("action", actionUrl); $.ajax({ type: "GET", url: actionUrl, data: param, beforeSend: function () { }, success: function (result) { debugger; $("#modal-content").html(result); $('#modal-form').modal('show'); }, error: function () { }, complete: function () { } }); } }; return oInit; }; </script>
api,services應用
以careteorUpdatePerson方法為例,我都是封裝好的。 調用的時候直接請求 "/api/services/app/user/Create"地址就可以了,其實這些代碼都是可以復用的,我們也可以封裝到一個共同的js頁面。我這里就沒有做這么詳細。
var careteorUpdatePerson = function (person, ajaxtype) { return abp.ajax({ url: Url, type: ajaxtype, async: false, data: JSON.stringify(person) }); }; var newPerson = { "id": $("#id").val(), "UserName": $("#txt_Surname").val(), "EmailAddress" : $("#txt_Name").val(), "Name": $("#txt_UserName").val(), "Surname": "test", "Password": "123456" }; careteorUpdatePerson(newPerson, ajaxtype).done(function (data) { toastr.warning('操作成功!'); var actionUrl = "@Url.Action("GetUsersList")"; $("#tb_departments").bootstrapTable('refresh', { url: actionUrl }); }); });
首先我們傳入的參數newPerson 必須與接口里面的需要的參數一致。而且接口里面自帶驗證。數據格式也必須一致。
界面及展示
比如這里郵箱地址我們隨便傳一個參數進去,他就會報錯。頁面上也是這樣的。
當然這里的提示我們是可以修改的。角色管理頁面的代碼也是一樣的。

@{ ViewBag.Title = "Index"; Layout = "~/Areas/Common/Views/Layout/_Layout.cshtml"; } <meta name="viewport" content="width=device-width" /> <script type="text/javascript"> $(function () { //1.初始化Table var oTable = new TableInit(); oTable.Init(); //2.初始化Button的點擊事件 var oButtonInit = new ButtonInit(); oButtonInit.Init(); }); var Url = "@Url.Action("GetUsersList")"; // var Url = "/api/services/app/user/GetAll()"; var TableInit = function () { var oTableInit = new Object(); //初始化Table oTableInit.Init = function () { $('#tb_departments').bootstrapTable({ // url: '../User/GetUsersList', url: Url, //請求后台的URL(*) method: 'get', //請求方式(*) toolbar: '#toolbar', //工具按鈕用哪個容器 striped: true, //是否顯示行間隔色 cache: false, //是否使用緩存,默認為true,所以一般情況下需要設置一下這個屬性(*) pagination: true, //是否顯示分頁(*) sortable: false, //是否啟用排序 sortOrder: "asc", //排序方式 queryParams: oTableInit.queryParams,//傳遞參數(*) sidePagination: "server", //分頁方式:client客戶端分頁,server服務端分頁(*) pageNumber: 1, //初始化加載第一頁,默認第一頁 pageSize: 2, //每頁的記錄行數(*) pageList: [10, 25, 50, 100], //可供選擇的每頁的行數(*) search: true, //是否顯示表格搜索,此搜索是客戶端搜索,不會進服務端,所以,個人感覺意義不大 strictSearch: true, showColumns: true, //是否顯示所有的列 showRefresh: true, //是否顯示刷新按鈕 minimumCountColumns: 2, //最少允許的列數 clickToSelect: true, //是否啟用點擊選中行 height: 500, //行高,如果沒有設置height屬性,表格自動根據記錄條數覺得表格高度 uniqueId: "ID", //每一行的唯一標識,一般為主鍵列 showToggle: true, //是否顯示詳細視圖和列表視圖的切換按鈕 cardView: false, //是否顯示詳細視圖 detailView: false, //是否顯示父子表 columns: [{ checkbox: true }, { field: 'Name', title: '角色名稱' }, { field: 'DisplayName', title: '描述' }, { field: 'CreationTime', title: '創建時間' }, { field: 'IsStatic', title: '是否啟用' }, ] }); }; //得到查詢的參數 oTableInit.queryParams = function (params) { var temp = { //這里的鍵的名字和控制器的變量名必須一直,這邊改動,控制器也需要改成一樣的 limit: params.limit, //頁面大小 offset: params.offset, //頁碼 departmentname: $("#txt_search_departmentname").val(), statu: $("#txt_search_statu").val() }; return temp; }; return oTableInit; }; var ButtonInit = function () { var oInit = new Object(); var postdata = {}; oInit.Init = function () { //初始化頁面上面的按鈕事件 //查詢角色 $("#btn_query").click(function () { var actionUrl = "@Url.Action("GetUsersList")"; m_pagerow = 0; $("#tb_departments").bootstrapTable('refresh', { url: actionUrl }); }); //新增角色 $("#btn_add").click(function () { $("#id").val(""); $("#txt_Name").val(""); $("#txt_DisplayName").val(""); $("#myModalLabel").text("新增"); $('#myModal').modal(); }); //新增角色 $("#btn_submit").click(function () { var Id = $("#id").val() == "" ? 0 : $("#id").val(); var Url = "/api/services/app/role/Update"; var ajaxtype = "put"; if ($("#id").val() == "") { Url = "/api/services/app/role/Create"; ajaxtype = "post"; } debugger; var careteorUpdatePerson = function (person, ajaxtype) { return abp.ajax({ url: Url, type: ajaxtype, async: false, data: JSON.stringify(person) }); }; var newPerson = { "id": $("#id").val(), "Name": $("#txt_Name").val(), "DisplayName": $("#txt_DisplayName").val(), "IsStatic": $("input[type='chekIsStatic']").is(':checked') ? true : false }; careteorUpdatePerson(newPerson, ajaxtype).done(function (data) { toastr.warning('操作成功!'); var actionUrl = "@Url.Action("GetUsersList")"; $("#tb_departments").bootstrapTable('refresh', { url: actionUrl }); }); }); //編輯角色 $("#btn_edit").click(function () { var arrselections = $("#tb_departments").bootstrapTable('getSelections'); if (arrselections.length > 1) { toastr.warning('只能選擇一行進行編輯'); return; } if (arrselections.length <= 0) { toastr.warning('請選擇有效數據'); return; } debugger; $("#id").val(arrselections[0].id); $("#txt_Name").val(arrselections[0].Name); $("#txt_DisplayName").val(arrselections[0].DisplayName); if (!arrselections[0].IsStatic) { $("#chekIsStatic").attr("checked", false); } $("#myModalLabel").text("修改"); $('#myModal').modal(); }); var deletePerson = function (person) { return abp.ajax({ url:'/api/services/app/role/Delete', type: 'delete', async: false, data: JSON.stringify(person) }); }; //刪除角色 $("#btn_delete").click(function () { var arrselections = $("#tb_departments").bootstrapTable('getSelections'); if (arrselections.length > 1) { toastr.warning('只能選擇一行進行編輯'); return; } if (arrselections.length <= 0) { toastr.warning('請選擇有效數據'); return; } var Id = arrselections[0].id; var newPerson = { "id": Id }; deletePerson(newPerson).done(function (data) { toastr.warning('操作成功!'); var actionUrl = "@Url.Action("GetUsersList")"; $("#tb_departments").bootstrapTable('refresh', { url: actionUrl }); }); }); //權限授權 $("#btn_authorize").click(function () { var arrselections = $("#tb_departments").bootstrapTable('getSelections'); if (arrselections.length > 1) { toastr.warning('只能選擇一個角色進行授權'); return; } if (arrselections.length <= 0) { toastr.warning('請選擇有效數據'); return; } var actionUrl = "@Url.Action("AuthorizePermission")"; var param = { id: arrselections[0].Id }; ShowModal_Authorize(actionUrl, param, "權限授權"); }); //模態框中“權限授權”保存 var $modal = $("#authorizeModal"); $("#btnSave", $modal).click(function () { var actionUrl = "@Url.Action("AuthorizePermission")"; SaveModal_Authorize(actionUrl); }); //模態框中“新增編輯角色”保存 var $formmodal = $("#modal-form"); $("#btnSave", $formmodal).click(function () { var $tb = $("#tb_departments"); SaveModal($tb); }); /*******彈出表單*********/ function ShowModal(actionUrl, param, title) { debugger; var $modal = $("#modal-form"); //表單初始化 $(".modal-title", $modal).html(title); $("#modal-content", $modal).attr("action", actionUrl); $.ajax({ type: "GET", url: actionUrl, data: param, beforeSend: function () { }, success: function (result) { debugger; $("#modal-content").html(result); $('#modal-form').modal('show'); }, error: function () { }, complete: function () { } }); } }; return oInit; }; </script> <section class="content-header"> <h1> 用戶明細 <small>advanced cxdmles</small> </h1> <ol class="breadcrumb"> <li><a href="#"><i class="fa fa-dashboard"></i> 主頁</a></li> <li><a href="#">用戶管理</a></li> <li class="active">用戶列表</li> </ol> </section> <section class="content"> <div class="panel-body" style="padding-bottom:0px;"> <div class="panel panel-default"> <div class="panel-heading">查詢條件</div> <div class="panel-body"> <form id="formSearch" class="form-horizontal"> <div class="form-group" style="margin-top:15px"> <label class="control-label col-sm-1" for="txt_search_departmentname">姓名</label> <div class="col-sm-3"> <input type="text" class="form-control" id="txt_search_departmentname"> </div> <label class="control-label col-sm-1" for="txt_search_statu">昵稱</label> <div class="col-sm-3"> <input type="text" class="form-control" id="txt_search_statu"> </div> <div class="col-sm-4" style="text-align:left;"> <button type="button" style="margin-left:50px" id="btn_query" class="btn btn-primary">查詢</button> </div> </div> </form> </div> </div> <div id="toolbar" class="btn-group"> <button id="btn_add" type="button" class="btn btn-success"> <span class="glyphicon glyphicon-plus" aria-hidden="true"></span>新增 </button> <button id="btn_edit" type="button" class="btn btn-warning"> <span class="glyphicon glyphicon-pencil" aria-hidden="true"></span>修改 </button> <button id="btn_delete" type="button" class="btn btn-danger"> <span class="glyphicon glyphicon-remove" aria-hidden="true"></span>刪除 </button> <button id="btn_authorize" type="button" class="btn btn-info "> <span class="glyphicon glyphicon-lock" aria-hidden="true"></span>授權 </button> </div> <table id="tb_departments"></table> </div> <div class="modal fade" id="myModal" tabindex="-1" role="dialog" aria-labelledby="myModalLabel"> <div class="modal-dialog" role="document"> <div class="modal-content"> <div class="modal-header"> <button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">×</span></button> <h4 class="modal-title" id="myModalLabel"></h4> </div> <div class="modal-body"> <div class="form-group"> <label for="txt_departmentname">角色名稱</label> <input type="text" name="id" class="form-control" id="id" placeholder="id" style="display:none"> <input type="text" name="txt_departmentname" class="form-control" id="txt_Name" placeholder="角色名稱"> </div> <div class="form-group"> <label for="txt_parentdepartment">角色描述</label> <input type="text" name="txt_parentdepartment" class="form-control" id="txt_DisplayName" placeholder="角色描述"> </div> @*<div class="form-group"> <label for="txt_departmentlevel">創建時間</label> <input type="text" name="txt_departmentlevel" class="form-control" id="txt_CreationTime" placeholder="創建時間"> </div>*@ <div class="form-group"> <label for="txt_departmentlevel">是否啟用</label> <div class="checkbox"> <label> <input type="checkbox" id="chekIsStatic" checked="checked"> </label> </div> </div> </div> <div class="modal-footer"> <button type="button" class="btn btn-default" data-dismiss="modal"><span class="glyphicon glyphicon-remove" aria-hidden="true"></span>關閉</button> <button type="button" id="btn_submit" class="btn btn-primary" data-dismiss="modal"><span class="glyphicon glyphicon-floppy-disk" aria-hidden="true"></span>保存</button> </div> </div> </div> </div> </section>
這里有共同的js我們已經放到 布局頁面。
現在用戶管理和角色管理功能已經實現,后面我會再做菜單管理,授權管理,做完基本上就完了,當然后面的也是重點。共同努力!
github 地址:https://github.com/Jimmey-Jiang/JCMS
module-zero角色管理
說說module-zero角色管理
角色實體
角色實體代表應用程序的角色。它應該從AbpRole類派生, 如下所示:
public class Role : AbpRole<Tenant, User> { //add your own role properties here }
這個類是在安裝模塊零時創建的。角色存儲在數據庫的AbpRoles表中。您可以將您的自定義屬性添加到角色類(並為更改創建數據庫遷移)。
AbpRole定義了一些屬性。最重要的是:
- 名稱:租戶中角色的唯一名稱。
- DisplayName:顯示角色的名稱。
- IsDefault:這個角色默認分配給新用戶嗎?
- IsStatic:這個角色是靜態的(預生成,不能被刪除)。
角色用於對權限進行分組。當用戶有一個角色,那么他/她將擁有該角色的所有權限。用戶可以有 多個角色。此用戶的權限將合並所有已分配角色的所有權限。
動態與靜態角色
在模塊零中,角色可以是動態的或靜態的:
- 靜態角色:一個靜態角色有一個已知的名字 (如'admin'),不能改變這個名字(我們可以改變 顯示名稱)。它在系統啟動時存在,不能被刪除。因此,我們可以編寫基於靜態角色名稱的代碼。
- 動態(非靜態)角色:我們可以在部署后創建動態角色。然后我們可以為該角色授予權限,我們可以將該角色分配給一些用戶,我們可以將其刪除。我們不能在開發時間知道動態角色的名字。
使用IsStatic屬性為其設置角色。另外,我們應該 在模塊的 PreInitialize上注冊靜態角色。假設我們對租戶有一個“Admin”靜態角色:
Configuration.Modules.Zero()。RoleManagement.StaticRoles.Add(new StaticRoleDefinition(“Admin”,MultiTenancySides.Tenant));
因此,模塊零將意識到靜態角色。
默認角色
一個或多個角色可以設置為默認值。默認角色分配給新增/注冊用戶。這不是開發時間屬性,可以在部署后進行設置或更改。使用IsDefault 屬性來設置它。
角色管理器
RoleManager是 為角色執行域邏輯的服務:
public class RoleManager : AbpRoleManager<Tenant, Role, User> { //... }
您可以注入並使用RoleManager來創建,刪除,更新角色,為角色授予權限等等。你可以在這里添加你自己的方法。此外,您可以 根據自己的需要重寫AbpRoleManager基類的任何方法。
像UserManager一樣,RoleManager的某些方法也會返回IdentityResult,而不是在某些情況下拋出異常。查看 用戶管理文檔以獲取更多信息。
>[ABP+AdminLTE+Bootstrap Table權限管理系統一期](http://www.cnblogs.com/anyushengcms/p/7325126.html)
[Github:https://github.com/Jimmey-Jiang/ABP-ASP.NET-Boilerplate-Project-CMS](https://github.com/Jimmey-Jiang/ABP-ASP.NET-Boilerplate-Project-CMS)
**返回總目錄:[ABP+AdminLTE+Bootstrap Table權限管理系統一期](http://www.cnblogs.com/anyushengcms/p/7325126.html)**
返回總目錄:ABP+AdminLTE+Bootstrap Table權限管理系統一期