ABP+AdminLTE+Bootstrap Table權(quán)限管理系統(tǒng)一期
Github:https://github.com/Jimmey-Jiang/ABP-ASP.NET-Boilerplate-Project-CMS
前往博客園總目錄:ABP+AdminLTE+Bootstrap Table權(quán)限管理系統(tǒng)一期
很多人說(shuō)ABP不適合高并發(fā)大型,有一定的道理,但是我覺(jué)得還是可以的,就看架構(gòu)師的能力了,我之前公司
就是ABP絕對(duì)百萬(wàn)數(shù)據(jù)級(jí)項(xiàng)目,是一個(gè)在線教育網(wǎng)站,涉及到平臺(tái),學(xué)院,院系,班級(jí),課程,學(xué)生等,一個(gè)平臺(tái)多少大學(xué),
一個(gè)大學(xué)多少院系,一個(gè)院系多少班級(jí)多少課程,其負(fù)責(zé)程度一點(diǎn)都不簡(jiǎn)單,不說(shuō)了,那是大神,比我在園子看到絕對(duì)大
多數(shù)架構(gòu)師都強(qiáng)悍.是我等仰望都對(duì)象.但是這不是停下腳步仰望的理由,只會(huì)是我們追求更強(qiáng)的腳步.
隨著軟件工作時(shí)間開(kāi)發(fā)經(jīng)驗(yàn)的不斷增加,我們發(fā)現(xiàn)其實(shí)很多工作都是重復(fù)機(jī)械的,而且隨著軟件復(fù)
雜度的不斷提升,以往依靠經(jīng)驗(yàn)來(lái)完成一些簡(jiǎn)單的增刪改查的做法已經(jīng)行不通了蜡坊。特別是用戶的要求越來(lái)越高典奉,希
望添加的功能越來(lái)多拇惋,目前這種開(kāi)發(fā)模式秒啦,已經(jīng)捉襟見(jiàn)肘。我很難想象如何在現(xiàn)有的模式下進(jìn)行多系統(tǒng)的持續(xù)集成
并添加一些新的特性虱朵。
開(kāi)發(fā)一個(gè)系統(tǒng)時(shí),我們不可避免的會(huì)使用各種框架钓账。數(shù)據(jù)持久層實(shí)現(xiàn)碴犬、日志、ASP[.NET]
(http://lib.csdn.net/base/dotnet)MVC梆暮、IOC以及自動(dòng)映射等服协。一個(gè)高質(zhì)量的軟件系統(tǒng)往往還有全局容錯(cuò),消息隊(duì)
列等組件啦粹。
其實(shí)偿荷,我們無(wú)非是希望在編程的時(shí)候治专,把大部分的注意力全部集中到業(yè)務(wù)實(shí)現(xiàn)上。不要過(guò)多的考
慮基礎(chǔ)的軟件結(jié)構(gòu)上的種種問(wèn)題遭顶。應(yīng)該有一個(gè)框框或者一種范式來(lái)提供基本的服務(wù)张峰,如日志、容錯(cuò)和AOP棒旗,DI等喘批。
稍微正規(guī)一點(diǎn)的公司經(jīng)過(guò)多年沉淀都形成了自己的內(nèi)部軟件框架,他們?cè)陂_(kāi)發(fā)軟件的時(shí)候并不是
從一片空白開(kāi)始的铣揉。而是從一個(gè)非常牢固的基礎(chǔ)平臺(tái)上開(kāi)始構(gòu)建的饶深。這樣大大提高了開(kāi)發(fā)速度,而且一種架構(gòu)往往
也決定了分工協(xié)作的模式逛拱。我們目前之所以無(wú)法分工協(xié)作敌厘,根本原因也是缺少一套成熟穩(wěn)定的基礎(chǔ)開(kāi)發(fā)架構(gòu)和工作
流程。
目前.NET上有不少開(kāi)源框架朽合。比如Apworks和ABP俱两。其中Apworks是中國(guó)人寫(xiě)的一套開(kāi)源框架。它是
一個(gè)全功能的曹步,不僅可以寫(xiě)分布式應(yīng)用宪彩,也可以寫(xiě)桌面應(yīng)用。ABP的全稱是Asp[.net]
(http://lib.csdn.net/base/dotnet)boilerplate project(asp.Net樣板工
程)讲婚。是github上非衬蚩祝活躍的一個(gè)開(kāi)源項(xiàng)目。它并沒(méi)有使用任何新的技術(shù)筹麸,只是由兩名架構(gòu)師將asp.net開(kāi)發(fā)中常用
的一些工具整合到了一起活合,并且部分實(shí)現(xiàn)了DDD的概念。是一個(gè)開(kāi)箱即用的框架物赶,可以作為asp.net分布式應(yīng)用的一
個(gè)良好起點(diǎn)白指。
使用框架當(dāng)然有代價(jià),你必須受到框架強(qiáng)API的侵入块差,抑或要使用他的方言侵续。而且這個(gè)框架想要吃
透,也要付出很大的學(xué)習(xí)成本憨闰。但是好處也是顯而易見(jiàn)的状蜗。業(yè)界頂尖的架構(gòu)師已經(jīng)為你搭建好了一套基礎(chǔ)架構(gòu),很
好的回應(yīng)了關(guān)于一個(gè)軟件系統(tǒng)應(yīng)該如何設(shè)計(jì)鹉动,如何規(guī)劃的問(wèn)題轧坎,并且提供了一套最佳實(shí)踐和范例。
學(xué)習(xí)雖然要付出成本泽示,但是經(jīng)過(guò)漫長(zhǎng)的跋涉缸血,我們從一無(wú)所知已經(jīng)站到了工業(yè)級(jí)開(kāi)發(fā)的門(mén)檻
上蜜氨。基于這個(gè)框架捎泻,我們可以很好的來(lái)劃分任務(wù)飒炎,進(jìn)行單元測(cè)試等。
大大降低了軟件出現(xiàn)BUG的幾率笆豁。
這節(jié)我就來(lái)說(shuō)一下在ABP module-zero基礎(chǔ)上做AdminLTE+Bootstrap Table的系統(tǒng),算是前面十一節(jié)的總結(jié)和擴(kuò)展.
首先我們依舊去官網(wǎng)根據(jù)abp模板創(chuàng)建解決方案.勾選上module-zero,然后創(chuàng)建數(shù)據(jù)庫(kù)連接,還原nuget包,然后update-database創(chuàng)建數(shù)據(jù)庫(kù).
接下來(lái)就是創(chuàng)建腳本更新數(shù)據(jù)庫(kù)了,以上這些都在前面的章節(jié)講到了,我就不做累述了,不明白可回去一下第一節(jié).
然后在home控制器下建ActionResult login,添加一個(gè)試圖頁(yè)面.加上自己的登陸頁(yè)面樣式j(luò)s等,這里我們就不用mvc的形式再在去請(qǐng)求控制器 了,我們直接請(qǐng)求webapi的登陸方法了.是的就是已經(jīng)搭好了swagger的然后請(qǐng)求/swagger/ui/index的Account接口.如圖.
既然前面講到ABP 對(duì)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);
});
其實(shí)這里我們還可以做一些再次封裝郎汪,方便在項(xiàng)目中去使用,就以登陸為例效果如下闯狱。
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"
}),
);
當(dāng)然這是在ABP原來(lái)封裝的效果上加上的煞赢,細(xì)心的你已經(jīng)發(fā)現(xiàn)這里多了兩個(gè)東西,一個(gè)是abp.ui.block哄孤,另外一個(gè)是abp.ui.setBusy照筑,這其實(shí)是一個(gè)阻止用戶重復(fù)提交,和正在提交繁忙狀態(tài)瘦陈,
其實(shí)就是一個(gè)遮罩層凝危。
這里是ABP集成的jquery.blockUI.js插件,該API使用一個(gè)透明的涂層(transparent overlay)來(lái)阻塞整個(gè)頁(yè)面或者該頁(yè)面上的一個(gè)元素双饥。這樣媒抠,用戶的點(diǎn)擊就無(wú)效了。當(dāng)保存一個(gè)表單或者加載一個(gè)區(qū)域(一個(gè)div或者整個(gè)頁(yè)面)時(shí)這是很有用的咏花。比如
另外abpjs中也對(duì)blockUI做了一些常用方法的封裝,設(shè)置阻塞abp.ui.block阀趴,取消阻塞abp.ui.unblock 昏翰,設(shè)置繁忙狀abp.ui.setBusy 和解除繁忙狀態(tài)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(); //阻塞整個(gè)頁(yè)面
abp.ui.block($('#MyDivElement')); //可以使用jQuery 選擇器..
abp.ui.block('#MyDivElement'); //..或者直接使用選擇器
abp.ui.unblock(); //解除阻塞整個(gè)頁(yè)面
abp.ui.unblock('#MyDivElement'); //解除阻塞特定的元素
UI Block API默認(rèn)使用jQuery的blockUI插件實(shí)現(xiàn)的。要是它生效刘急,你應(yīng)該包含它的javascript文件棚菊,然后在頁(yè)面中包含abp.blockUI.js作為適配器。
另外一個(gè)就是busy 該API用于使得某些頁(yè)面或者元素處于繁忙狀態(tài)叔汁。比如统求,你可能想阻塞一個(gè)表單,然后當(dāng)提交表單至服務(wù)器時(shí)展示一個(gè)繁忙的指示器据块。例子:
abp.ui.setBusy('#MyLoginForm');
abp.ui.clearBusy('#MyLoginForm');
效果就是上面的繁忙效果码邻。
該參數(shù)應(yīng)該是一個(gè)選擇器(如‘#MyLoginForm’)或者jQuery選擇器(如$('#MyLoginForm'))。要使得整個(gè)頁(yè)面處于繁忙狀態(tài)另假,你可以傳入null(或者'body')作為選擇器像屋。setBusy函數(shù)第二個(gè)參數(shù)接收一個(gè)promise(約定),當(dāng)該約定完成時(shí)會(huì)自動(dòng)清除繁忙的狀態(tài)边篮。因?yàn)閍bp.ajax返回promise己莺,我們可以直接將它作為promise傳入奏甫。要學(xué)習(xí)慣于promise更多的東西,查看jQuery的Deferred凌受。
UI Busy API是使用spin.js實(shí)現(xiàn)的阵子。要讓它生效,應(yīng)該包含它的javascript文件胜蛉,然后在頁(yè)面中包含abp.spin.js作為適配器款筑。
經(jīng)過(guò)上面的努力,我們得登陸也已經(jīng)做好了腾么。登陸成功之后我們要做事的事情就是一個(gè)保存token另外一個(gè)就是路由的重定向了奈梳。
token在ABP中很重要,我們?cè)谡?qǐng)求 /api/Account會(huì)反饋一個(gè)token解虱,我們?cè)诘顷懙臅r(shí)候就把token存到cookie中攘须,以方便后面的使用。如登陸中的 abp.auth.setToken("Bearer " + data); 那ABP是怎么樣設(shè)置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常用的存取和清除的方法。頁(yè)面上緩存的cookie名字就是Abp.AuthToken悍汛,獲取的時(shí)候可以直接獲取捞魁。
我們?cè)谝呀?jīng)添加了域,所以這里登陸成功之后直接把url指向/admin/userinfo/index离咐。當(dāng)然在/Areas/Common/Views/Layout里面我們已經(jīng)AdminLTE的布局了谱俭,包括菜單已經(jīng)加載出來(lái)了,其實(shí)現(xiàn)在服務(wù)層的時(shí)候漏了一些東西宵蛀,我們這里補(bǔ)上昆著,ABP既然是一個(gè)框架
那么在創(chuàng)建Service的時(shí)候自然要包含基礎(chǔ)增刪查改的方法,那么這時(shí)候IAsyncCrudAppService就派上用場(chǎng)了术陶。這里我們以模板IModulesService講一下凑懂。首先我們創(chuàng)建好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>
/// 模塊編號(hào)
/// </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集成了某個(gè)接口,那么DTO也要繼承這個(gè)接口的DTO梧宫,不然再繼承IAsyncCrudAppService就會(huì)報(bào)錯(cuò)接谨。
比如面的model繼承Entity<int> 那么DTO也要繼承EntityDto<int>.
然后我們看一下IAsyncCrudAppService需要哪么參數(shù)。
這里都可以看得很清楚了塘匣,包括增刪查改的DTO這里我比較懶脓豪,都用了一個(gè)。
接口:
public interface IModulesService : IAsyncCrudAppService<MeunDto, int, PagedResultRequestDto, MeunDto, MeunDto> // IApplicationService
{
}
實(shí)現(xiàn)
public class ModulesService : AsyncCrudAppService<Meun, MeunDto, int, PagedResultRequestDto, MeunDto, MeunDto>, IModulesService
{
public ModulesService(IRepository<Meun, int> repository) : base(repository)
{
}
}
然后馆铁,我們?cè)赼piJCMSWebApiModule方法下加上.WithConventionalVerbs() 這樣我們就可以看到特定的HTTP前綴跑揉,不然全是post,HTTP動(dòng)詞是通過(guò)方法名的前綴決定的:
Get:方法名以Get開(kāi)頭。
Put:方法名以Put或Update開(kāi)頭历谍。
Delete:方法名以Delete或Remove開(kāi)頭现拒。
Post:方法名以Post或Create開(kāi)頭。
否則望侈,Post是HTTP動(dòng)詞的默認(rèn)值印蔬。
我們可以通過(guò)對(duì)特定的方法使用WithVerb方法或者HTTP特性來(lái)覆蓋上述慣例。
就這樣脱衙,我們?cè)跇I(yè)務(wù)層中常用的增刪改查的方法就誕生了侥猬。
驗(yàn)證一下,傳入?yún)?shù)捐韩,結(jié)果沒(méi)毛病退唠,可用。當(dāng)然這里根據(jù)自己的需要可以重寫(xiě)這些方法的荤胁。頁(yè)面和前面的頁(yè)面差不多瞧预,沒(méi)啥講的,這里頁(yè)面增刪改查都已經(jīng)實(shí)現(xiàn)仅政。
首先我們看一下userinfo 頁(yè)面垢油,這里我們也根據(jù)abp ajax的封裝和 swagger的應(yīng)用做了一些改變,首先看頁(yè)面圆丹,我們不通過(guò)控制器去獲取創(chuàng)建和修改刪除的方法了滩愁。控制器只有一個(gè)帶分頁(yè)的獲取的方法 這是因?yàn)锽ootstrap table必須要以這樣的json結(jié)構(gòu)返回
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標(biāo)簽打上的辫封,不需要abp做的特殊封裝硝枉。js頁(yè)面的一些方法。
<script type="text/javascript">
$(function () {
//1.初始化Table
var oTable = new TableInit();
oTable.Init();
//2.初始化Button的點(diǎn)擊事件
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, //請(qǐng)求后臺(tái)的URL(*)
method: 'get', //請(qǐng)求方式(*)
toolbar: '#toolbar', //工具按鈕用哪個(gè)容器
striped: true, //是否顯示行間隔色
cache: false, //是否使用緩存秸讹,默認(rèn)為true檀咙,所以一般情況下需要設(shè)置一下這個(gè)屬性(*)
pagination: true, //是否顯示分頁(yè)(*)
sortable: false, //是否啟用排序
sortOrder: "asc", //排序方式
queryParams: oTableInit.queryParams,//傳遞參數(shù)(*)
sidePagination: "server", //分頁(yè)方式:client客戶端分頁(yè),server服務(wù)端分頁(yè)(*)
pageNumber: 1, //初始化加載第一頁(yè)璃诀,默認(rèn)第一頁(yè)
pageSize: 2, //每頁(yè)的記錄行數(shù)(*)
pageList: [10, 25, 50, 100], //可供選擇的每頁(yè)的行數(shù)(*)
search: true, //是否顯示表格搜索,此搜索是客戶端搜索蔑匣,不會(huì)進(jìn)服務(wù)端劣欢,所以,個(gè)人感覺(jué)意義不大
strictSearch: true,
showColumns: true, //是否顯示所有的列
showRefresh: true, //是否顯示刷新按鈕
minimumCountColumns: 2, //最少允許的列數(shù)
clickToSelect: true, //是否啟用點(diǎn)擊選中行
height: 500, //行高裁良,如果沒(méi)有設(shè)置height屬性凿将,表格自動(dòng)根據(jù)記錄條數(shù)覺(jué)得表格高度
uniqueId: "ID", //每一行的唯一標(biāo)識(shí),一般為主鍵列
showToggle: true, //是否顯示詳細(xì)視圖和列表視圖的切換按鈕
cardView: false, //是否顯示詳細(xì)視圖
detailView: false, //是否顯示父子表
columns: [{
checkbox: true
}, {
field: 'UserName',
title: '姓名'
}, {
field: 'EmailAddress',
title: '郵箱'
}, {
field: 'Surname',
title: '真是姓名'
}, {
field: 'Name',
title: '角色'
}, ]
});
};
//得到查詢的參數(shù)
oTableInit.queryParams = function (params) {
var temp = { //這里的鍵的名字和控制器的變量名必須一直价脾,這邊改動(dòng)牧抵,控制器也需要改成一樣的
limit: params.limit, //頁(yè)面大小
offset: params.offset, //頁(yè)碼
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 () {
//初始化頁(yè)面上面的按鈕事件
//查詢角色
$("#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('只能選擇一行進(jìn)行編輯');
return;
}
if (arrselections.length <= 0) {
toastr.warning('請(qǐng)選擇有效數(shù)據(jù)');
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會(huì)按照如下寫(xiě)法,做一個(gè)簡(jiǎn)單的封裝來(lái)重用ajax,此處框架可以幫你生成簡(jiǎn)單的調(diào)用方法
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('只能選擇一行進(jìn)行編輯');
return;
}
if (arrselections.length <= 0) {
toastr.warning('請(qǐng)選擇有效數(shù)據(jù)');
return;
}
var Id = arrselections[0].id;
var newPerson = {
"id": Id
};
//直接調(diào)用方法犀变,如何生成上面的調(diào)用方法可以參考源碼中的Abp.Web.Api項(xiàng)目中/ WebApi/ Controllers/ Scripting/ jQuery下的實(shí)現(xiàn)
deletePerson(newPerson).done(function (data) {
toastr.warning('操作成功!');
var actionUrl = "@Url.Action("GetUsersList")";
$("#tb_departments").bootstrapTable('refresh', { url: actionUrl });
});
});
//權(quán)限授權(quán)
$("#btn_authorize").click(function () {
var arrselections = $("#tb_departments").bootstrapTable('getSelections');
if (arrselections.length > 1) {
toastr.warning('只能選擇一個(gè)角色進(jìn)行授權(quán)');
return;
}
if (arrselections.length <= 0) {
toastr.warning('請(qǐng)選擇有效數(shù)據(jù)');
return;
}
var actionUrl = "@Url.Action("AuthorizePermission")";
var param = { id: arrselections[0].Id };
ShowModal_Authorize(actionUrl, param, "權(quán)限授權(quán)");
});
//模態(tài)框中“權(quán)限授權(quán)”保存
var $modal = $("#authorizeModal");
$("#btnSave", $modal).click(function () {
var actionUrl = "@Url.Action("AuthorizePermission")";
SaveModal_Authorize(actionUrl);
});
//模態(tài)框中“新增編輯角色”保存
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>
以careteorUpdatePerson方法為例妹孙,我都是封裝好的。 調(diào)用的時(shí)候直接請(qǐng)求 "/api/services/app/user/Create"地址就可以了获枝,其實(shí)這些代碼都是可以復(fù)用的蠢正,我們也可以封裝到一個(gè)共同的js頁(yè)面。我這里就沒(méi)有做這么詳細(xì)省店。
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 });
});
});
首先我們傳入的參數(shù)newPerson 必須與接口里面的需要的參數(shù)一致嚣崭。而且接口里面自帶驗(yàn)證。數(shù)據(jù)格式也必須一致懦傍。
比如這里郵箱地址我們隨便傳一個(gè)參數(shù)進(jìn)去雹舀,他就會(huì)報(bào)錯(cuò)。頁(yè)面上也是這樣的粗俱。
當(dāng)然這里的提示我們是可以修改的说榆。角色管理頁(yè)面的代碼也是一樣的。
@{
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的點(diǎn)擊事件
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, //請(qǐng)求后臺(tái)的URL(*)
method: 'get', //請(qǐng)求方式(*)
toolbar: '#toolbar', //工具按鈕用哪個(gè)容器
striped: true, //是否顯示行間隔色
cache: false, //是否使用緩存源梭,默認(rèn)為true娱俺,所以一般情況下需要設(shè)置一下這個(gè)屬性(*)
pagination: true, //是否顯示分頁(yè)(*)
sortable: false, //是否啟用排序
sortOrder: "asc", //排序方式
queryParams: oTableInit.queryParams,//傳遞參數(shù)(*)
sidePagination: "server", //分頁(yè)方式:client客戶端分頁(yè),server服務(wù)端分頁(yè)(*)
pageNumber: 1, //初始化加載第一頁(yè)废麻,默認(rèn)第一頁(yè)
pageSize: 2, //每頁(yè)的記錄行數(shù)(*)
pageList: [10, 25, 50, 100], //可供選擇的每頁(yè)的行數(shù)(*)
search: true, //是否顯示表格搜索荠卷,此搜索是客戶端搜索,不會(huì)進(jìn)服務(wù)端烛愧,所以油宜,個(gè)人感覺(jué)意義不大
strictSearch: true,
showColumns: true, //是否顯示所有的列
showRefresh: true, //是否顯示刷新按鈕
minimumCountColumns: 2, //最少允許的列數(shù)
clickToSelect: true, //是否啟用點(diǎn)擊選中行
height: 500, //行高,如果沒(méi)有設(shè)置height屬性怜姿,表格自動(dòng)根據(jù)記錄條數(shù)覺(jué)得表格高度
uniqueId: "ID", //每一行的唯一標(biāo)識(shí)慎冤,一般為主鍵列
showToggle: true, //是否顯示詳細(xì)視圖和列表視圖的切換按鈕
cardView: false, //是否顯示詳細(xì)視圖
detailView: false, //是否顯示父子表
columns: [{
checkbox: true
}, {
field: 'Name',
title: '角色名稱'
}, {
field: 'DisplayName',
title: '描述'
}, {
field: 'CreationTime',
title: '創(chuàng)建時(shí)間'
}, {
field: 'IsStatic',
title: '是否啟用'
}, ]
});
};
//得到查詢的參數(shù)
oTableInit.queryParams = function (params) {
var temp = { //這里的鍵的名字和控制器的變量名必須一直,這邊改動(dòng)沧卢,控制器也需要改成一樣的
limit: params.limit, //頁(yè)面大小
offset: params.offset, //頁(yè)碼
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 () {
//初始化頁(yè)面上面的按鈕事件
//查詢角色
$("#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('只能選擇一行進(jìn)行編輯');
return;
}
if (arrselections.length <= 0) {
toastr.warning('請(qǐng)選擇有效數(shù)據(jù)');
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('只能選擇一行進(jìn)行編輯');
return;
}
if (arrselections.length <= 0) {
toastr.warning('請(qǐng)選擇有效數(shù)據(jù)');
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 });
});
});
//權(quán)限授權(quán)
$("#btn_authorize").click(function () {
var arrselections = $("#tb_departments").bootstrapTable('getSelections');
if (arrselections.length > 1) {
toastr.warning('只能選擇一個(gè)角色進(jìn)行授權(quán)');
return;
}
if (arrselections.length <= 0) {
toastr.warning('請(qǐng)選擇有效數(shù)據(jù)');
return;
}
var actionUrl = "@Url.Action("AuthorizePermission")";
var param = { id: arrselections[0].Id };
ShowModal_Authorize(actionUrl, param, "權(quán)限授權(quán)");
});
//模態(tài)框中“權(quán)限授權(quán)”保存
var $modal = $("#authorizeModal");
$("#btnSave", $modal).click(function () {
var actionUrl = "@Url.Action("AuthorizePermission")";
SaveModal_Authorize(actionUrl);
});
//模態(tài)框中“新增編輯角色”保存
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>
用戶明細(xì)
<small>advanced cxdmles</small>
</h1>
<ol class="breadcrumb">
<li><a href="#"><i class="fa fa-dashboard"></i> 主頁(yè)</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>授權(quán)
</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">創(chuàng)建時(shí)間</label>
<input type="text" name="txt_departmentlevel" class="form-control" id="txt_CreationTime" placeholder="創(chuàng)建時(shí)間">
</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>關(guān)閉</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我們已經(jīng)放到 布局頁(yè)面蚁堤。
現(xiàn)在用戶管理和角色管理功能已經(jīng)實(shí)現(xiàn),后面我會(huì)再做菜單管理但狭,授權(quán)管理披诗,做完基本上就完了,當(dāng)然后面的也是重點(diǎn)立磁。共同努力呈队!
github 地址:https://github.com/Jimmey-Jiang/JCMS
返回簡(jiǎn)書(shū)總目錄:ABP+AdminLTE+Bootstrap Table權(quán)限管理系統(tǒng)一期
前往博客園總目錄:ABP+AdminLTE+Bootstrap Table權(quán)限管理系統(tǒng)一期